add btFileUtils::toLower to convert a string (char*) to lower case

URDF import demo: add COLLADA .dae file support
add FiniteElementMethod demo, extracted from the OpenTissue library (under the zlib license)
don't crash if loading an invalid STL file
add comparison with Assimp for COLLADA file loading (disabled by default, to avoid library dependency)
Gwen: disable some flags that make the build incompatible
This commit is contained in:
erwin coumans
2014-10-29 13:18:34 -07:00
parent aaaf8dc4e2
commit 4b665fa82b
139 changed files with 17704 additions and 46 deletions

View File

@@ -0,0 +1,366 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_AOF_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_AOF_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/grid_gradient.h>
#include <OpenTissue/core/containers/grid/util/grid_coord2idx.h>
#include <OpenTissue/core/containers/grid/util/grid_idx2coord.h>
#include <OpenTissue/core/containers/grid/util/grid_gradient_at_point.h>
#include <cmath>
namespace OpenTissue
{
namespace grid
{
namespace detail
{
/**
* Compute Average Outward Flux at designated nodal position of a signed distance grid.
*
*
* @param phi The signed distance grid.
* @param i The i'th index of the node.
* @param j The j'th index of the node.
* @param k The k'th index of the node.
* @param scale Default value is 0.5, this determines the scale on which the flux is computed. 0.5 correponds to ``voxel-based''.
*
* @return The flux value.
*/
template<typename grid_type>
inline typename grid_type::value_type
compute_aof_value(
grid_type const & phi
, size_t const & i
, size_t const & j
, size_t const & k
, double scale = 0.5
)
{
using std::min;
using std::sqrt;
typedef typename grid_type::iterator iterator;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename grid_type::value_type value_type;
typedef typename grid_type::math_types math_types;
typedef typename math_types::vector3_type vector3_type;
typedef typename math_types::real_type real_type;
real_type dx = phi.dx()*scale;
real_type dy = phi.dy()*scale;
real_type dz = phi.dz()*scale;
vector3_type n[26];
vector3_type dp[26];
dp[0] = vector3_type( dx, 0, 0);
dp[1] = vector3_type(-dx, 0, 0);
dp[2] = vector3_type( 0, dy, 0);
dp[3] = vector3_type( 0,-dy, 0);
dp[4] = vector3_type( 0, 0, dz);
dp[5] = vector3_type( 0, 0,-dz);
dp[6] = vector3_type( dx, dy, dz);
dp[7] = vector3_type( dx, dy,-dz);
dp[8] = vector3_type( dx,-dy, dz);
dp[9] = vector3_type( dx,-dy,-dz);
dp[10] = vector3_type(-dx, dy, dz);
dp[11] = vector3_type(-dx, dy,-dz);
dp[12] = vector3_type(-dx,-dy, dz);
dp[13] = vector3_type(-dx,-dy,-dz);
dp[14] = vector3_type( dx, dy, 0);
dp[15] = vector3_type( dx,-dy, 0);
dp[16] = vector3_type(-dx, dy, 0);
dp[17] = vector3_type(-dx,-dy, 0);
dp[18] = vector3_type( dx, 0, dz);
dp[19] = vector3_type( dx, 0,-dz);
dp[20] = vector3_type(-dx, 0, dz);
dp[21] = vector3_type(-dx, 0,-dz);
dp[22] = vector3_type( 0, dy, dz);
dp[23] = vector3_type( 0, dy,-dz);
dp[24] = vector3_type( 0,-dy, dz);
dp[25] = vector3_type( 0,-dy,-dz);
for(size_t cnt=0;cnt<26u;++cnt)
n[cnt] = unit(dp[cnt]);
vector3_type p;
idx2coord(phi,i,j,k,p);
real_type flux = real_type();
for(size_t cnt=0;cnt<26u;++cnt)
{
vector3_type q = p + dp[cnt];
vector3_type g = gradient_at_point(phi,q);
flux += unit(g)*n[cnt];
}
flux /= 26.0;
return static_cast<value_type>(flux);
}
} //namespace detail
/**
* Average Outward Flux.
*
* @param phi A the distance grid.
* @param F A grid containing the values of the average outward flux.
*/
template<typename grid_type>
inline void aof(
grid_type const & phi
, grid_type & F
)
{
using std::min;
using std::sqrt;
typedef typename grid_type::iterator iterator;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename grid_type::value_type value_type;
typedef typename grid_type::math_types math_types;
typedef typename math_types::vector3_type vector3_type;
typedef typename math_types::real_type real_type;
value_type const unused = phi.unused();
size_t const & I = phi.I();
size_t const & J = phi.J();
size_t const & K = phi.K();
F.create(phi.min_coord(),phi.max_coord(),I,J,K);
real_type dx = phi.dx()*0.5;
real_type dy = phi.dy()*0.5;
real_type dz = phi.dz()*0.5;
//real_type rho = sqrt(dx*dx+dy*dy+dz*dz);
vector3_type n[26];
vector3_type dp[26];
dp[0] = vector3_type( dx, 0, 0);
dp[1] = vector3_type(-dx, 0, 0);
dp[2] = vector3_type( 0, dy, 0);
dp[3] = vector3_type( 0,-dy, 0);
dp[4] = vector3_type( 0, 0, dz);
dp[5] = vector3_type( 0, 0,-dz);
dp[6] = vector3_type( dx, dy, dz);
dp[7] = vector3_type( dx, dy,-dz);
dp[8] = vector3_type( dx,-dy, dz);
dp[9] = vector3_type( dx,-dy,-dz);
dp[10] = vector3_type(-dx, dy, dz);
dp[11] = vector3_type(-dx, dy,-dz);
dp[12] = vector3_type(-dx,-dy, dz);
dp[13] = vector3_type(-dx,-dy,-dz);
dp[14] = vector3_type( dx, dy, 0);
dp[15] = vector3_type( dx,-dy, 0);
dp[16] = vector3_type(-dx, dy, 0);
dp[17] = vector3_type(-dx,-dy, 0);
dp[18] = vector3_type( dx, 0, dz);
dp[19] = vector3_type( dx, 0,-dz);
dp[20] = vector3_type(-dx, 0, dz);
dp[21] = vector3_type(-dx, 0,-dz);
dp[22] = vector3_type( 0, dy, dz);
dp[23] = vector3_type( 0, dy,-dz);
dp[24] = vector3_type( 0,-dy, dz);
dp[25] = vector3_type( 0,-dy,-dz);
for(size_t i=0;i<26u;++i)
n[i] = unit(dp[i]);
//n[0] = unit(vector3_type( 1, 0, 0));
//n[1] = unit(vector3_type(-1, 0, 0));
//n[2] = unit(vector3_type( 0, 1, 0));
//n[3] = unit(vector3_type( 0,-1, 0));
//n[4] = unit(vector3_type( 0, 0, 1));
//n[5] = unit(vector3_type( 0, 0,-1));
//n[6] = unit(vector3_type( 1, 1, 1));
//n[7] = unit(vector3_type( 1, 1,-1));
//n[8] = unit(vector3_type( 1,-1, 1));
//n[9] = unit(vector3_type( 1,-1,-1));
//n[10] = unit(vector3_type(-1, 1, 1));
//n[11] = unit(vector3_type(-1, 1,-1));
//n[12] = unit(vector3_type(-1,-1, 1));
//n[13] = unit(vector3_type(-1,-1,-1));
//n[14] = unit(vector3_type( 1, 1, 0));
//n[15] = unit(vector3_type( 1,-1, 0));
//n[16] = unit(vector3_type(-1, 1, 0));
//n[17] = unit(vector3_type(-1,-1, 0));
//n[18] = unit(vector3_type( 1, 0, 1));
//n[19] = unit(vector3_type( 1, 0,-1));
//n[20] = unit(vector3_type(-1, 0, 1));
//n[21] = unit(vector3_type(-1, 0,-1));
//n[22] = unit(vector3_type( 0, 1, 1));
//n[23] = unit(vector3_type( 0, 1,-1));
//n[24] = unit(vector3_type( 0,-1, 1));
//n[25] = unit(vector3_type( 0,-1,-1));
//for(size_t i=0;i<26u;++i)
// dp[i] = n[i]*rho;
iterator f = F.begin();
const_index_iterator v = phi.begin();
const_index_iterator vend = phi.end();
for(;v!=vend;++v,++f)
{
if((*v)==unused)
{
(*f) = value_type(); //--- should default to zero!!!
continue;
}
size_t i = v.i();
size_t j = v.j();
size_t k = v.k();
vector3_type p;
idx2coord(phi,i,j,k,p);
real_type flux = real_type();
for(size_t i=0;i<26u;++i)
{
vector3_type q = p + dp[i];
vector3_type g = gradient_at_point(phi,q);
flux += unit(g)*n[i];
}
flux /= 26.0;
(*f) = static_cast<value_type>(flux);
}
//vector3_type n_mpp = unit(vector3_type( -1, 1, 1));
//vector3_type n_mp0 = unit(vector3_type( -1, 1, 0));
//vector3_type n_mpm = unit(vector3_type( -1, 1, -1));
//vector3_type n_m0p = unit(vector3_type( -1, 0, 1));
//vector3_type n_m00 = unit(vector3_type( -1, 0, 0));
//vector3_type n_m0m = unit(vector3_type( -1, 0, -1));
//vector3_type n_mmp = unit(vector3_type( -1, -1, 1));
//vector3_type n_mm0 = unit(vector3_type( -1, -1, 0));
//vector3_type n_mmm = unit(vector3_type( -1, -1, -1));
//vector3_type n_0pp = unit(vector3_type( 0, 1, 1));
//vector3_type n_0p0 = unit(vector3_type( 0, 1, 0));
//vector3_type n_0pm = unit(vector3_type( 0, 1, -1));
//vector3_type n_00p = unit(vector3_type( 0, 0, 1));
//vector3_type n_000 = unit(vector3_type( 0, 0, 0));
//vector3_type n_00m = unit(vector3_type( 0, 0, -1));
//vector3_type n_0mp = unit(vector3_type( 0, -1, 1));
//vector3_type n_0m0 = unit(vector3_type( 0, -1, 0));
//vector3_type n_0mm = unit(vector3_type( 0, -1, -1));
//vector3_type n_ppp = unit(vector3_type( 1, 1, 1));
//vector3_type n_pp0 = unit(vector3_type( 1, 1, 0));
//vector3_type n_ppm = unit(vector3_type( 1, 1, -1));
//vector3_type n_p0p = unit(vector3_type( 1, 0, 1));
//vector3_type n_p00 = unit(vector3_type( 1, 0, 0));
//vector3_type n_p0m = unit(vector3_type( 1, 0, -1));
//vector3_type n_pmp = unit(vector3_type( 1, -1, 1));
//vector3_type n_pm0 = unit(vector3_type( 1, -1, 0));
//vector3_type n_pmm = unit(vector3_type( 1, -1, -1));
//vector3_type g_mpp;
//vector3_type g_mp0;
//vector3_type g_mpm;
//vector3_type g_m0p;
//vector3_type g_m00;
//vector3_type g_m0m;
//vector3_type g_mmp;
//vector3_type g_mm0;
//vector3_type g_mmm;
//vector3_type g_0pp;
//vector3_type g_0p0;
//vector3_type g_0pm;
//vector3_type g_00p;
//vector3_type g_000;
//vector3_type g_00m;
//vector3_type g_0mp;
//vector3_type g_0m0;
//vector3_type g_0mm;
//vector3_type g_ppp;
//vector3_type g_pp0;
//vector3_type g_ppm;
//vector3_type g_p0p;
//vector3_type g_p00;
//vector3_type g_p0m;
//vector3_type g_pmp;
//vector3_type g_pm0;
//vector3_type g_pmm;
//iterator f = F.begin();
//const_index_iterator v = phi.begin();
//const_index_iterator vend = phi.end();
//for(;v!=vend;++v,++f)
//{
// if((*v)==unused)
// {
// (*f) = value_type(); //--- should default to zero!!!
// continue;
// }
// size_t i = v.i();
// size_t j = v.j();
// size_t k = v.k();
// size_t im1 = ( i ) ? i - 1 : 0;
// size_t jm1 = ( j ) ? j - 1 : 0;
// size_t km1 = ( k ) ? k - 1 : 0;
// size_t ip1 = min( i + 1u, I - 1u );
// size_t jp1 = min( j + 1u, J - 1u );
// size_t kp1 = min( k + 1u, K - 1u );
// gradient(phi, im1, jp1, kp1, g_mpp );
// gradient(phi, im1, jp1, k, g_mp0 );
// gradient(phi, im1, jp1, km1, g_mpm );
// gradient(phi, im1, j, kp1, g_m0p );
// gradient(phi, im1, j, k, g_m00 );
// gradient(phi, im1, j, km1, g_m0m );
// gradient(phi, im1, jm1, kp1, g_mmp );
// gradient(phi, im1, jm1, k, g_mm0 );
// gradient(phi, im1, jm1, km1, g_mmm );
// gradient(phi, i, jp1, kp1, g_0pp );
// gradient(phi, i, jp1, k, g_0p0 );
// gradient(phi, i, jp1, km1, g_0pm );
// gradient(phi, i, j, kp1, g_00p );
// gradient(phi, i, j, k, g_000 );
// gradient(phi, i, j, km1, g_00m );
// gradient(phi, i, jm1, kp1, g_0mp );
// gradient(phi, i, jm1, k, g_0m0 );
// gradient(phi, i, jm1, km1, g_0mm );
// gradient(phi, ip1, jp1, kp1, g_ppp );
// gradient(phi, ip1, jp1, k, g_pp0 );
// gradient(phi, ip1, jp1, km1, g_ppm );
// gradient(phi, ip1, j, kp1, g_p0p );
// gradient(phi, ip1, j, k, g_p00 );
// gradient(phi, ip1, j, km1, g_p0m );
// gradient(phi, ip1, jm1, kp1, g_pmp );
// gradient(phi, ip1, jm1, k, g_pm0 );
// gradient(phi, ip1, jm1, km1, g_pmm );
// real_type flux = real_type();
// flux += unit(g_mpp) * n_mpp;
// flux += unit(g_mp0) * n_mp0;
// flux += unit(g_mpm) * n_mpm;
// flux += unit(g_m0p) * n_m0p;
// flux += unit(g_m00) * n_m00;
// flux += unit(g_m0m) * n_m0m;
// flux += unit(g_mmp) * n_mmp;
// flux += unit(g_mm0) * n_mm0;
// flux += unit(g_mmm) * n_mmm;
// flux += unit(g_0pp) * n_0pp;
// flux += unit(g_0p0) * n_0p0;
// flux += unit(g_0pm) * n_0pm;
// flux += unit(g_00p) * n_00p;
// flux += unit(g_000) * n_000;
// flux += unit(g_00m) * n_00m;
// flux += unit(g_0mp) * n_0mp;
// flux += unit(g_0m0) * n_0m0;
// flux += unit(g_0mm) * n_0mm;
// flux += unit(g_ppp) * n_ppp;
// flux += unit(g_pp0) * n_pp0;
// flux += unit(g_ppm) * n_ppm;
// flux += unit(g_p0p) * n_p0p;
// flux += unit(g_p00) * n_p00;
// flux += unit(g_p0m) * n_p0m;
// flux += unit(g_pmp) * n_pmp;
// flux += unit(g_pm0) * n_pm0;
// flux += unit(g_pmm) * n_pmm;
// flux /= 26.0;
// (*f) = static_cast<value_type>(flux);
//}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_AOF_H
#endif

View File

@@ -0,0 +1,86 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_APPROXIMATE_GAUSSIAN_FILTER_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_APPROXIMATE_GAUSSIAN_FILTER_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/grid_box_filter.h>
#include <OpenTissue/core/containers/grid/util/grid_translate.h>
namespace OpenTissue
{
namespace grid
{
/**
* Fast convolution by an approximate "integer" guassian filter.
* This just applies several box_filter's (boxsize=size and order times),
* and is only efficient for low orders.
* If size is even, the order must also be even for the resulting image to lay on the same grid
* (else translated 0.5 voxel towards (0,0,0) ).
* @param src Source grid to be convolved.
* @param order Order of filter. Corresponds to the number of times the boxfilter is applied.
* @param size Size of filter.
* @param dst Upon return, contains the filtered grid.
*/
template <class grid_type>
inline void approximate_gaussian_filter(grid_type const& src, size_t order, size_t size, grid_type& dst)
{
typedef typename grid_type::index_vector index_vector;
dst=src;
for(size_t i=0; i<order; ++i)
{
box_filter(dst,size,dst);
// recenter image by 1 voxel for every second application of the box_filter when the size is odd
if (i>0 && (i%2) && !(size%2))
{
std::cout << "--calling translate()" << std::endl;
translate(dst, index_vector(1,1,1), dst);
}
}
}
/**
* Approximate Gaussian filter with compensation on image borders.
* Attenuation on border regions is compensated.
* This is equivalent to Gaussian filtering using only filter coefficients
* that are inside the "shape" being considered.
* @param src Source grid to be convolved.
* @param order Order of filter. Corresponds to the number of times the boxfilter is applied.
* @param size Size of filter.
* @param dst Upon return, contains the filtered grid.
*/
template <class grid_type>
inline void approximate_gaussian_filter_border_correct(grid_type const& src, size_t order, size_t size, grid_type &dst)
{
grid_type lowFreq=src;
// apply filter in normal fashion
approximate_gaussian_filter(lowFreq, order, size, lowFreq);
// compensate for border regions in filtering
// FIXME: refactor this!
/* {
Image3Df smask(src.Size());
smask.Fill(1);
approximate_gaussian_filter(smask,order,size,smask);
for(typename grid_type::index_iterator p=lowFreq.begin(); p!=lowFreq.end(); ++p)
{
if(smask(p.Pos()))
{
*p/=smask(p.Pos());
}
}
}*/
dst=lowFreq;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_APPROXIMATE_GAUSSIAN_FILTER_H
#endif

View File

@@ -0,0 +1,90 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_AVERAGE_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_AVERAGE_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
namespace OpenTissue
{
namespace grid
{
template < typename grid_type >
inline void average( grid_type & phi )
{
using std::min;
typedef typename grid_type::index_iterator iterator;
typedef typename grid_type::value_type value_type;
grid_type tmp = phi;
size_t I = phi.I();
size_t J = phi.J();
size_t K = phi.K();
iterator pend = phi.end();
iterator p = phi.begin();
iterator t = tmp.begin();
for(;p!=pend;++p,++t)
{
size_t i = p.i();
size_t j = p.j();
size_t k = p.k();
static size_t idx[27];
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
idx[0] = ( kp1 * J + jp1 ) * I + im1;
idx[1] = ( k * J + jp1 ) * I + im1;
idx[2] = ( km1 * J + jp1 ) * I + im1;
idx[3] = ( kp1 * J + j ) * I + im1;
idx[4] = ( k * J + j ) * I + im1;
idx[5] = ( km1 * J + j ) * I + im1;
idx[6] = ( kp1 * J + jm1 ) * I + im1;
idx[7] = ( k * J + jm1 ) * I + im1;
idx[8] = ( km1 * J + jm1 ) * I + im1;
idx[9] = ( kp1 * J + jp1 ) * I + i;
idx[10] = ( k * J + jp1 ) * I + i;
idx[11] = ( km1 * J + jp1 ) * I + i;
idx[12] = ( kp1 * J + j ) * I + i;
idx[13] = ( k * J + j ) * I + i;
idx[14] = ( km1 * J + j ) * I + i;
idx[15] = ( kp1 * J + jm1 ) * I + i;
idx[16] = ( k * J + jm1 ) * I + i;
idx[17] = ( km1 * J + jm1 ) * I + i;
idx[18] = ( kp1 * J + jp1 ) * I + ip1;
idx[19] = ( k * J + jp1 ) * I + ip1;
idx[20] = ( km1 * J + jp1 ) * I + ip1;
idx[21] = ( kp1 * J + j ) * I + ip1;
idx[22] = ( k * J + j ) * I + ip1;
idx[23] = ( km1 * J + j ) * I + ip1;
idx[24] = ( kp1 * J + jm1 ) * I + ip1;
idx[25] = ( k * J + jm1 ) * I + ip1;
idx[26] = ( km1 * J + jm1 ) * I + ip1;
value_type avg = value_type(); //--- default constructed zero by standard!!!
for(size_t i=0;i<27u;++i)
avg += phi(idx[i]);
avg /= value_type(25);
*t = avg;
}
phi = tmp;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_AVERAGE_H
#endif

View File

@@ -0,0 +1,76 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_BISECTION_LINE_SEARCH_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_BISECTION_LINE_SEARCH_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/grid_gradient_at_point.h>
namespace OpenTissue
{
namespace grid
{
/**
* Grid Bisection Line Search
*
* @param q_a
* @param q_b
* @param phi
* @param maximize If true the bisection method tries to find the maximimum value between q_a and q_b otherwise it tries to find the minimum value.
*
* @return The point that maximizes the value of phi on the line between q_a and q_b.
*/
template<typename vector3_type,typename grid_type>
inline vector3_type bisection_line_search(vector3_type q_a, vector3_type q_b, grid_type & phi, bool maximize = true)
{
using std::fabs;
typedef typename vector3_type::value_type real_type;
real_type const precision = 10e-5;//OpenTissue::math::working_precision<real_type>(100);
real_type const too_small_interval = sqr_length(q_b-q_a)*0.0001; //--- 1/100'th of distance!
vector3_type n = unit(gradient_at_point(phi,q_a));
vector3_type r;
real_type const sign = maximize? 1.0 : -1.0;
bool forever = true;
do
{
vector3_type q_c = (q_a + q_b)*.5;
if( sqr_length(q_a - q_b) < too_small_interval )
{
r = q_c;
break;
}
vector3_type dir = unit(gradient_at_point(phi,q_c));
real_type n_dot_dir = inner_prod(n , dir)*sign;
if(fabs(n_dot_dir) < precision)
{
r = q_c;
break;
}
if(n_dot_dir > 0)
{
q_a = q_c;
}
if(n_dot_dir < 0)
{
q_b = q_c;
}
}
while (forever);
return r;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_BISECTION_LINE_SEARCH_H
#endif

View File

@@ -0,0 +1,139 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_BLOCKIFY_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_BLOCKIFY_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <iostream>
#include <cmath>
#include <algorithm>
namespace OpenTissue
{
namespace grid
{
/**
* Level Set Blockifier.
* This function takes a level set grid and re-initializes it into
* small cubic blocks (-1 inside and +1 outside).
*
* @param phi The level set grid.
*/
template<typename grid_type>
inline void blockify(grid_type & phi)
{
typedef typename grid_type::value_type value_type;
typedef typename grid_type::index_iterator iterator;
value_type unused = phi.unused();
value_type inside = value_type(-1.0);
value_type outside = value_type( 1.0);
size_t offset = 7u;
size_t spacing = 11u;
size_t block = offset + spacing;
iterator begin = phi.begin();
iterator end = phi.end();
iterator p;
for(p=begin;p!=end;++p)
{
if(*p==unused)
continue;
bool inside_i = ((p.i() % block)>offset);
bool inside_j = ((p.j() % block)>offset);
bool inside_k = ((p.k() % block)>offset);
if(inside_i && inside_j && inside_k)
*p = inside;
else
*p = outside;
}
}
/** Initialize a grid with a pattern of boxes of width offset.
*
* @param phi The grid to initialize.
* @param inside Value to fill inside blocks
* @param outside Value to fill outside blocks
* @param offset The offset from the borders.
* @param spacing The width, height, depth and half the spacing of boxes.
*/
template<typename grid_type,typename value_type>
inline void blockify(grid_type & phi, value_type inside, value_type outside, size_t offset, size_t spacing)
{
typedef typename grid_type::value_type internal_type;
typedef typename grid_type::index_iterator iterator;
internal_type unused = phi.unused();
internal_type inside_ = (internal_type)( inside );
internal_type outside_ = (internal_type)( outside );
size_t block = offset + spacing;
iterator begin = phi.begin();
iterator end = phi.end();
iterator p;
for(p=begin;p!=end;++p)
{
if(*p==unused)
continue;
bool inside_i = ((p.i() % block)>offset);
bool inside_j = ((p.j() % block)>offset);
bool inside_k = ((p.k() % block)>offset);
if(inside_i && inside_j && inside_k)
*p = inside_;
else
*p = outside_;
}
}
/** Initialize a slice of a grid with a pattern of boxes of width offset.
*
* @param phi The grid to initialize.
* @param inside Value to fill inside blocks
* @param outside Value to fill outside blocks
* @param offset The offset from the borders.
* @param spacing The width, height, and half the spacing of boxes.
* @param slice The slice in z-depth that needs to be filled
*/
template<typename grid_type,typename value_type>
inline void blockify(grid_type & phi, value_type inside, value_type outside, size_t offset, size_t spacing, size_t slice)
{
typedef typename grid_type::value_type internal_type;
typedef typename grid_type::index_iterator iterator;
internal_type unused = phi.unused();
internal_type inside_ = (internal_type)( inside );
internal_type outside_ = (internal_type)( outside );
size_t block = offset + spacing;
iterator begin = phi.begin();
iterator end = phi.end();
iterator p;
for(p=begin;p!=end;++p)
{
if (p.k()!=slice)
continue;
if(*p==unused)
continue;
bool inside_i = ((p.i() % block)>offset);
bool inside_j = ((p.j() % block)>offset);
if(inside_i && inside_j)
*p = inside_;
else
*p = outside_;
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_BLOCKIFY_H
#endif

View File

@@ -0,0 +1,47 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_CLOSING_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_CLOSING_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/grid_dilation.h>
#include <OpenTissue/core/containers/grid/util/grid_erosion.h>
namespace OpenTissue
{
namespace grid
{
/**
* Closing Operation.
*
* @param phi Input level set.
* @param radius Radius of spherical structural element.
* @param dt Time-step to use in update.
* @param psi Output levelset. Note if input is a signed distance map then output may not be a signed distance map, thus you may need to redistance output levelset.
*/
template<
typename grid_type_in
, typename real_type
, typename grid_type_out
>
inline void closing(
grid_type_in const & phi
, real_type const & radius
, real_type const & dt
, grid_type_out & psi
)
{
erosion(phi,radius,dt,psi);
dilation(psi,radius,dt,psi);
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_CLOSING_H
#endif

View File

@@ -0,0 +1,49 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_COMPUTE_SIGN_FUNCTION_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_COMPUTE_SIGN_FUNCTION_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
namespace OpenTissue
{
namespace grid
{
template < typename grid_type >
inline void compute_sign_function( grid_type const & phi, grid_type & S0 )
{
using std::sqrt;
typedef typename grid_type::value_type real_type;
typedef typename grid_type::const_index_iterator const_iterator;
typedef typename grid_type::index_iterator iterator;
S0.create(phi.min_coord(),phi.max_coord(),phi.I(),phi.J(),phi.K());
// yellowbook p67.
real_type delta = phi.dx()*phi.dx() + phi.dy()*phi.dy() + phi.dz()*phi.dz();
const_iterator begin = phi.begin();
const_iterator end = phi.end();
for ( const_iterator idx = begin;idx!=end;++idx)
{
size_t i = idx.i();
size_t j = idx.j();
size_t k = idx.k();
real_type c = phi( i,j,k );
S0( i,j,k ) = c / ( sqrt( c * c + delta ) );//---TODO: Verify this formula!!!
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_COMPUTE_SIGN_FUNCTION_H
#endif

View File

@@ -0,0 +1,65 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_COORD_TO_IDX_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_COORD_TO_IDX_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
namespace OpenTissue
{
namespace grid
{
/**
* Coordinate 2 Voxel Indices.
* This method computes the indices (i,j,k) of
* the voxel containing the specified point.
*
* The voxel index of the voxel containing the points is equal to index
* of the grid node of the containing voxel with lowest coordinates
* (ie. lower-left-back grid node).
*
* @param grid The grid.
* @param point The point.
* @param i Upon return this parameter contains the index of the voxel along the I-axe.
* @param j Upon return this parameter contains the index of the voxel along the J-axe.
* @param k Upon return this parameter contains the index of the voxel along the K-axe.
*/
template <typename grid_type, typename vector3_type>
inline void coord2idx( grid_type const & grid, vector3_type const & point, size_t & i, size_t & j, size_t & k )
{
using std::floor;
typedef typename vector3_type::value_type real_type;
real_type const & dx = grid.dx();
real_type const & dy = grid.dy();
real_type const & dz = grid.dz();
real_type const & mx = grid.min_coord( 0 );
real_type const & my = grid.min_coord( 1 );
real_type const & mz = grid.min_coord( 2 );
real_type xval = ( point( 0 ) - mx ) / dx;
i = static_cast<size_t>( floor( xval ) );
if ( ( xval - i ) > .5 )
++i;
real_type yval = ( point( 1 ) - my ) / dy;
j = static_cast<size_t>( floor( yval ) );
if ( ( yval - j ) > .5 )
++j;
real_type zval = ( point( 2 ) - mz ) / dz;
k = static_cast<size_t>( floor( zval ) );
if ( ( zval - k ) > .5 )
++k;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_COORD_TO_IDX_H
#endif

View File

@@ -0,0 +1,116 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_CROP_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_CROP_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
#include <OpenTissue/core/containers/grid/util/grid_idx2coord.h>
#include <OpenTissue/core/math/math_vector3.h>
namespace OpenTissue
{
namespace grid
{
/**
* Crop grid to bounding box that do not include treshold.
* Can be used to automatically crop emptyness from scanned data.
* @param M Original grid to be cropped.
* @param m Destination grid.
* @param treshold Maximum value that needs to be cropped.
* @return Upon return the destination grid m contains the cropped grid.
*/
template < typename grid_type >
inline void crop(grid_type const & M, grid_type & m, typename grid_type::value_type const & treshold)
{
using std::min;
using std::max;
typedef typename grid_type::math_types math_types;
typedef typename math_types::vector3_type vector3_type;
typedef OpenTissue::math::Vector3<size_t> index_vector;
index_vector min_idx( M.I(), M.J(), M.K() );
index_vector max_idx( 0, 0, 0 );
for(size_t k=0; k<M.K(); ++k )
for(size_t j=0; j<M.J(); ++j )
for(size_t i=0; i<M.I(); ++i )
{
if ( M(i,j,k) > treshold )
{
min_idx = min( min_idx, index_vector(i,j,k) );
max_idx = max( max_idx, index_vector(i,j,k) );
}
}
index_vector new_dim = (max_idx - min_idx) + index_vector(1);
vector3_type min_coord,max_coord;
idx2coord(M, min_idx(0), min_idx(1), min_idx(2),min_coord);
idx2coord(M, max_idx(0), max_idx(1), max_idx(2),max_coord);
m.create( min_coord, max_coord, new_dim(0), new_dim(1), new_dim(2) );
size_t i_offset = min_idx(0);
size_t j_offset = min_idx(1);
size_t k_offset = min_idx(2);
for(size_t k=0; k<m.K(); ++k )
for(size_t j=0; j<m.J(); ++j )
for(size_t i=0; i<m.I(); ++i )
{
m(i,j,k) = M( i+i_offset, j+j_offset, k+k_offset );
}
}
/**
* Crop grid to user specified bounding box.
* @param M Original grid to be cropped.
* @param m Destination grid.
* @param min_i Lower i-coord of bounding box.
* @param min_j Lower j-coord of bounding box.
* @param min_k Lower k-coord of bounding box.
* @param max_i Upper i-coord of bounding box.
* @param max_j Upper j-coord of bounding box.
* @param max_k Upper k-coord of bounding box.
* @return Upon return the destination grid m contains the cropped grid.
*/
template < typename grid_type >
inline void crop(
grid_type const & M
, grid_type & m
, size_t min_i
, size_t min_j
, size_t min_k
, size_t max_i
, size_t max_j
, size_t max_k
)
{
typedef typename grid_type::math_types math_types;
typedef typename math_types::vector3_type vector3_type;
typedef typename grid_type::index_iterator index_iterator;
vector3_type min_coord,max_coord;
idx2coord(M, min_i, min_j, min_k, min_coord);
idx2coord(M, max_i, max_j, max_k, max_coord);
m.create( min_coord, max_coord, max_i-min_i+1, max_j-min_j+1, max_k-min_k+1 );
for(size_t k=0; k<m.K(); ++k )
for(size_t j=0; j<m.J(); ++j )
for(size_t i=0; i<m.I(); ++i )
{
m(i,j,k) = M( i+min_i, j+min_j, k+min_k );
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_CROP_H
#endif

View File

@@ -0,0 +1,199 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_CURVATURE_FLOW_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_CURVATURE_FLOW_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/grid_mean_curvature.h>
namespace OpenTissue
{
namespace grid
{
/**
* Calculate curvature flow.
*
* WARNING: Unexpected behavior if input and output level sets are the same.
*
*
* @param phi Input level set.
* @param mu Mean Curvature coefficient.
* @param dt Time-step to use in update.
* @param psi Output levelset. Note if input is a signed distance map
* then output may not be a signed distance map, thus
* you may need to redistance output levelset.
*/
template<
typename grid_type
, typename real_type
>
inline void curvature_flow(
grid_type const & phi
, real_type const & mu
, real_type const & dt
, grid_type & psi
)
{
using std::min;
using std::max;
using std::sqrt;
typedef typename grid_type::value_type value_type;
typedef typename grid_type::iterator iterator;
typedef typename grid_type::index_iterator index_iterator;
typedef typename grid_type::const_index_iterator const_index_iterator;
assert(mu>0 || !"curvature_flow(): curvature coefficient must be positive");
assert(dt>0 || !"curvature_flow(): time-step must be positive");
size_t I = phi.I();
size_t J = phi.J();
size_t K = phi.K();
real_type dx = static_cast<real_type> ( phi.dx() );
real_type dy = static_cast<real_type> ( phi.dy() );
real_type dz = static_cast<real_type> ( phi.dz() );
real_type m_inv_dx2 = static_cast<real_type> ( 1.0 / (dx*dx) );
real_type m_inv_dy2 = static_cast<real_type> ( 1.0 / (dy*dy) );
real_type m_inv_dz2 = static_cast<real_type> ( 1.0 / (dz*dz) );
real_type m_inv_4dxy = static_cast<real_type> ( 0.25 / (dx*dy) );
real_type m_inv_4dxz = static_cast<real_type> ( 0.25 / (dx*dz) );
real_type m_inv_4dyz = static_cast<real_type> ( 0.25 / (dy*dz) );
real_type min_delta = static_cast<real_type> (min(dx,min(dy,dz) ));
real_type kappa_limit = static_cast<real_type> ( 1.0 / ( max(dx, max(dy,dz) ) ) );
value_type zero = static_cast<value_type>(0.0);
grid_type F = phi; //--- speed function
if(&psi != &phi)
psi = phi;
iterator fbegin = F.begin();
index_iterator sbegin = psi.begin();
index_iterator send = psi.end();
real_type threshold = static_cast<real_type>(10e-15); //--- small number used to avoid division by zero!!!
real_type time = static_cast<real_type>(0.0);
while (time < dt)
{
value_type max_F = zero; //--- maximum speed, used to setup CFL condition
iterator f = fbegin;
index_iterator s = sbegin;
for(;s!=send; ++s,++f)
{
size_t i = s.i();
size_t j = s.j();
size_t k = s.k();
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1, I - 1 );
size_t jp1 = min( j + 1, J - 1 );
size_t kp1 = min( k + 1, K - 1 );
size_t idx_000 = ( k * J + j ) * I + i;
size_t idx_m00 = ( k * J + j ) * I + im1;
size_t idx_p00 = ( k * J + j ) * I + ip1;
size_t idx_0m0 = ( k * J + jm1 ) * I + i;
size_t idx_0p0 = ( k * J + jp1 ) * I + i;
size_t idx_00m = ( km1 * J + j ) * I + i;
size_t idx_00p = ( kp1 * J + j ) * I + i;
size_t idx_pp0 = ( k * J + jp1 ) * I + ip1;
size_t idx_mp0 = ( k * J + jp1 ) * I + im1;
size_t idx_pm0 = ( k * J + jm1 ) * I + ip1;
size_t idx_mm0 = ( k * J + jm1 ) * I + im1;
size_t idx_p0p = ( kp1 * J + j ) * I + ip1;
size_t idx_m0p = ( kp1 * J + j ) * I + im1;
size_t idx_p0m = ( km1 * J + j ) * I + ip1;
size_t idx_m0m = ( km1 * J + j ) * I + im1;
size_t idx_0pp = ( kp1 * J + jp1 ) * I + i;
size_t idx_0pm = ( km1 * J + jp1 ) * I + i;
size_t idx_0mp = ( kp1 * J + jm1 ) * I + i;
size_t idx_0mm = ( km1 * J + jm1 ) * I + i;
real_type d000 = 2.0 * psi( idx_000 );
real_type dp00 = psi( idx_p00 );
real_type dm00 = psi( idx_m00 );
real_type d0p0 = psi( idx_0p0 );
real_type d0m0 = psi( idx_0m0 );
real_type d00p = psi( idx_00p );
real_type d00m = psi( idx_00m );
real_type dpp0 = psi( idx_pp0 );
real_type dmp0 = psi( idx_mp0 );
real_type dpm0 = psi( idx_pm0 );
real_type dmm0 = psi( idx_mm0 );
real_type dp0p = psi( idx_p0p );
real_type dm0p = psi( idx_m0p );
real_type dp0m = psi( idx_p0m );
real_type dm0m = psi( idx_m0m );
real_type d0pp = psi( idx_0pp );
real_type d0pm = psi( idx_0pm );
real_type d0mp = psi( idx_0mp );
real_type d0mm = psi( idx_0mm );
//---- Hessian matrix is defines as
//
// | d/(dx*dx) d(/(dx*dy) d/(dx*dz) |
// H = | d/(dy*dx) d(/(dy*dy) d/(dy*dz) | phi
// | d/(dz*dx) d(/(dz*dy) d/(dz*dz) |
//
//
//--- Following is a central diff approximation
real_type psi_x = (dp00 - dm00) * m_inv_dx2;
real_type psi_y = (d0p0 - d0m0) * m_inv_dy2;
real_type psi_z = (d00p - d00m) * m_inv_dz2;
real_type psi_xx = ( dp00 + dm00 - d000 ) * m_inv_dx2;
real_type psi_yy = ( d0p0 + d0m0 - d000 ) * m_inv_dy2;
real_type psi_zz = ( d00p + d00m - d000 ) * m_inv_dz2;
real_type psi_xy = ( dpp0 - dmp0 - dpm0 + dmm0 ) * m_inv_4dxy;
real_type psi_xz = ( dp0p - dm0p - dp0m + dm0m ) * m_inv_4dxz;
real_type psi_yz = ( d0pp - d0pm - d0mp + d0mm ) * m_inv_4dyz;
real_type norm_grad_psi = sqrt( (psi_x*psi_x) + (psi_y*psi_y) + (psi_z*psi_z) );
real_type kappa =
(
(psi_x*psi_x)*psi_yy
+ (psi_x*psi_x)*psi_zz
+ (psi_y*psi_y)*psi_xx
+ (psi_y*psi_y)*psi_zz
+ (psi_z*psi_z)*psi_xx
+ (psi_z*psi_z)*psi_yy
- 2*(psi_x*psi_y)*psi_xy
- 2*(psi_x*psi_z)*psi_xz
- 2*(psi_y*psi_z)*psi_yz
)
/
(norm_grad_psi*norm_grad_psi*norm_grad_psi + threshold );
kappa = max( kappa, -kappa_limit );
kappa = min( kappa, kappa_limit );
*f = static_cast<value_type>(mu * kappa);
max_F = max(max_F, std::fabs(*f));
}
real_type time_left = max( dt - time, 0.0 );
if(time_left <= 0)
return;
value_type time_step = static_cast<value_type>( min( time_left, min_delta / (max_F) ) );
std::cout << "\tcurvature_flow() : timestep = " << time_step << std::endl;
for(s=sbegin, f=fbegin;s!=send;++s,++f)
(*s) = (*s) + time_step * (*f);
time += time_step;
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_CURVATURE_FLOW_H
#endif

View File

@@ -0,0 +1,57 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_DILATION_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_DILATION_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace grid
{
/**
* Dilate level set.
*
* @param phi Input level set.
* @param radius Radius of spherical structural element.
* @param dt Time-step to use in update.
* @param psi Output levelset. Note if input is a signed distance map then output may not be a signed distance map, thus you may need to redistance output levelset.
*/
template<
typename grid_type_in
, typename real_type
, typename grid_type_out
>
inline void dilation(
grid_type_in const & phi
, real_type const & radius
, real_type const & dt
, grid_type_out & psi
)
{
typedef typename grid_type_in::value_type input_type;
typedef typename grid_type_out::value_type output_type;
typedef typename grid_type_in::const_index_iterator input_iterator;
assert(radius>0 || !"dilation(): radius must be positive");
assert(dt>0 || !"dilation(): time-step must be positive");
input_iterator input_begin = phi.begin();
input_iterator input_end = phi.end();
input_iterator input;
input_type unused = phi.unused();
for(input=input_begin;input!=input_end;++input)
if(*input!=unused)
psi(input.get_index()) = *input - dt*radius;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_DILATION_H
#endif

View File

@@ -0,0 +1,167 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_DIV_GRAD_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_DIV_GRAD_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/grid_gradient.h>
#include <OpenTissue/core/containers/grid/util/grid_coord2idx.h>
#include <cmath>
namespace OpenTissue
{
namespace grid
{
/**
* Div-Grad.
* Computes the divergence of the gradient of a specified field. Ie. the flux of the gradient field!
*
* @param phi A the grid.
* @param M A grid containing the values of the divergence of the gradient field of phi.
*/
template<typename grid_type>
inline void div_grad(
grid_type const & phi
, grid_type & M
)
{
using std::min;
typedef OpenTissue::math::Vector3< typename grid_type::value_type> vector3_type;
typedef typename grid_type::iterator iterator;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename grid_type::value_type value_type;
typedef typename grid_type::math_types math_types;
typedef typename math_types::real_type real_type;
size_t const & I = phi.I();
size_t const & J = phi.J();
size_t const & K = phi.K();
M.create(phi.min_coord(),phi.max_coord(),I,J,K);
static value_type unused = phi.unused();
vector3_type /*g000,*/gp00,gm00,g0p0,g0m0,g00p,g00m;
vector3_type gppp,gppm,gpmp,gpmm,gmpp,gmpm,gmmp,gmmm;
vector3_type gpp0, gpm0, gmp0, gmm0, gp0p, gp0m, gm0p, gm0m, g0pp, g0pm, g0mp, g0mm;
static vector3_type np00 = unit(vector3_type( 1, 0, 0));
static vector3_type nm00 = unit(vector3_type(-1, 0, 0));
static vector3_type n0p0 = unit(vector3_type( 0, 1, 0));
static vector3_type n0m0 = unit(vector3_type( 0,-1, 0));
static vector3_type n00p = unit(vector3_type( 0, 0, 1));
static vector3_type n00m = unit(vector3_type( 0, 0,-1));
static vector3_type nppp = unit(vector3_type( 1, 1, 1));
static vector3_type nppm = unit(vector3_type( 1, 1,-1));
static vector3_type npmp = unit(vector3_type( 1,-1, 1));
static vector3_type npmm = unit(vector3_type( 1,-1,-1));
static vector3_type nmpp = unit(vector3_type(-1, 1, 1));
static vector3_type nmpm = unit(vector3_type(-1, 1,-1));
static vector3_type nmmp = unit(vector3_type(-1,-1, 1));
static vector3_type nmmm = unit(vector3_type(-1,-1,-1));
static vector3_type npp0 = unit(vector3_type( 1, 1, 0));
static vector3_type npm0 = unit(vector3_type( 1,-1, 0));
static vector3_type nmp0 = unit(vector3_type(-1, 1, 0));
static vector3_type nmm0 = unit(vector3_type(-1,-1, 0));
static vector3_type np0p = unit(vector3_type( 1, 0, 1));
static vector3_type np0m = unit(vector3_type( 1, 0,-1));
static vector3_type nm0p = unit(vector3_type(-1, 0, 1));
static vector3_type nm0m = unit(vector3_type(-1, 0,-1));
static vector3_type n0pp = unit(vector3_type( 0, 1, 1));
static vector3_type n0pm = unit(vector3_type( 0, 1,-1));
static vector3_type n0mp = unit(vector3_type( 0,-1, 1));
static vector3_type n0mm = unit(vector3_type( 0,-1,-1));
iterator m = M.begin();
const_index_iterator pbegin = phi.begin();
const_index_iterator pend = phi.end();
const_index_iterator p = pbegin;
for(;p!=pend;++p,++m)
{
if((*p)==unused)
{
*m = value_type(); //--- should default to zero!!!
continue;
}
size_t i = p.i();
size_t j = p.j();
size_t k = p.k();
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
gradient(phi, ip1, j, k, gp00);
gradient(phi, im1, j, k, gm00);
gradient(phi, i, jp1, k, g0p0);
gradient(phi, i, jm1, k, g0m0);
gradient(phi, i, j, kp1, g00p);
gradient(phi, i, j, km1, g00m);
gradient(phi, ip1, jp1, k, gpp0);
gradient(phi, ip1, jm1, k, gpm0);
gradient(phi, im1, jp1, k, gmp0);
gradient(phi, im1, jm1, k, gmm0);
gradient(phi, ip1, j, kp1, gp0p);
gradient(phi, ip1, j, km1, gp0m);
gradient(phi, im1, j, kp1, gm0p);
gradient(phi, im1, j, km1, gm0m);
gradient(phi, i, jp1, kp1, g0pp);
gradient(phi, i, jp1, km1, g0pm);
gradient(phi, i, jm1, kp1, g0mp);
gradient(phi, i, jm1, km1, g0mm);
gradient(phi, ip1, jp1, kp1, gppp);
gradient(phi, ip1, jp1, km1, gppm);
gradient(phi, ip1, jm1, kp1, gpmp);
gradient(phi, ip1, jm1, km1, gpmm);
gradient(phi, im1, jp1, kp1, gmpp);
gradient(phi, im1, jp1, km1, gmpm);
gradient(phi, ip1, jm1, kp1, gmmp);
gradient(phi, im1, jm1, km1, gmmm);
real_type flux = real_type(); //--- should default to zero!!!
flux += gp00 * np00;
flux += gm00 * nm00;
flux += g0p0 * n0p0;
flux += g0m0 * n0m0;
flux += g00p * n00p;
flux += g00m * n00m;
flux += gpp0 * npp0;
flux += gpm0 * npm0;
flux += gmp0 * nmp0;
flux += gmm0 * nmm0;
flux += gp0p * np0p;
flux += gp0m * np0m;
flux += gm0p * nm0p;
flux += gm0m * nm0m;
flux += g0pp * n0pp;
flux += g0pm * n0pm;
flux += g0mp * n0mp;
flux += g0mm * n0mm;
flux += gppp * nppp;
flux += gppm * nppm;
flux += gpmp * npmp;
flux += gpmm * npmm;
flux += gmpp * nmpp;
flux += gmpm * nmpm;
flux += gmmp * nmmp;
flux += gmmm * nmmm;
(*m) = static_cast<value_type>(flux);
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_DIV_GRAD_H
#endif

View File

@@ -0,0 +1,79 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_ENCLOSING_INDICES_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_ENCLOSING_INDICES_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
namespace OpenTissue
{
namespace grid
{
/**
* Get Enclosing Indices.
* Finds enclosing node indices for a given point.
* Assumes that the point is strictly inside the volume.
*
* @param grid The grid.
* @param point Vector with coordinates of the point.
* @param i0 Upon return, this parameter contains the i-index of the lower-left-back node.
* @param j0 Upon return, this parameter contains the j-index of the lower-left-back node.
* @param k0 Upon return, this parameter contains the k-index of the lower-left-back node.
* @param i1 Upon return, this parameter contains the i-index of the upper-right-front node.
* @param j1 Upon return, this parameter contains the j-index of the upper-right-front node.
* @param k1 Upon return, this parameter contains the k-index of the upper-right-front node.
*/
template <typename grid_type, typename vector3_type>
inline void enclosing_indices(
grid_type const & grid
, vector3_type const & point
, size_t& i0
, size_t& j0
, size_t& k0
, size_t& i1
, size_t& j1
, size_t& k1
)
{
using std::max;
using std::min;
using std::floor;
typedef typename vector3_type::value_type real_type;
real_type const & dx = grid.dx();
real_type const & dy = grid.dy();
real_type const & dz = grid.dz();
size_t const & I = grid.I();
size_t const & J = grid.J();
size_t const & K = grid.K();
vector3_type range = grid.max_coord() - grid.min_coord();
vector3_type diff = point - grid.min_coord();
diff = min( max(diff, vector3_type( real_type() ) ) , range);
diff(0) /= dx;
diff(1) /= dy;
diff(2) /= dz;
i0 = static_cast<size_t>( floor( diff(0) ) );
j0 = static_cast<size_t>( floor( diff(1) ) );
k0 = static_cast<size_t>( floor( diff(2) ) );
i1 = ( i0 + 1 ) % I;
j1 = ( j0 + 1 ) % J;
k1 = ( k0 + 1 ) % K;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_ENCLOSING_INDICES_H
#endif

View File

@@ -0,0 +1,56 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_EROSION_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_EROSION_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace grid
{
/**
* Erode level set.
*
* @param phi Input level set.
* @param radius Radius of spherical structural element.
* @param dt Time-step to use in update.
* @param psi Output levelset. Note if input is a signed distance map then output may not be a signed distance map, thus you may need to redistance output levelset.
*/
template<
typename grid_type_in
, typename real_type
, typename grid_type_out
>
inline void erosion(
grid_type_in const & phi
, real_type const & radius
, real_type const & dt
, grid_type_out & psi
)
{
typedef typename grid_type_in::value_type input_type;
typedef typename grid_type_out::value_type output_type;
typedef typename grid_type_in::const_index_iterator input_iterator;
assert(radius>0 || !"erosion(): radius must be positive");
assert(dt>0 || !"erosion(): time-step must be positive");
input_iterator input_begin = phi.begin();
input_iterator input_end = phi.end();
input_iterator input;
input_type unused = phi.unused();
for(input=input_begin;input!=input_end;++input)
if(*input!=unused)
psi(input.get_index()) = *input + dt*radius;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_EROSION_H
#endif

View File

@@ -0,0 +1,136 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_EXTRAPOLATION_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_EXTRAPOLATION_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
#include <OpenTissue/core/containers/grid/util/gradient.h>
#include <OpenTissue/core/containers/grid/util/grid_compute_sign_function.h>
#include <OpenTissue/core/math/math_vector3.h>
namespace OpenTissue
{
namespace grid
{
/**
*
* @param max_iterations The maximum number of iterations allowed to do extrapolation.
* @param stead_threshold The threshold value used to test for steady state.
*/
template < typename grid_type >
inline void extrapolation(
grid_type & S
, grid_type const & phi
, size_t max_iterations = 10
// , double steady_threshold = 0.05
)
{
using std::min;
using std::max;
using std::fabs;
typedef OpenTissue::math::Vector3< typename grid_type::value_type> vector3_type;
typedef typename grid_type::iterator iterator;
typedef typename grid_type::index_iterator index_iterator;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename grid_type::value_type value_type;
typedef typename grid_type::math_types math_types;
typedef typename math_types::real_type real_type;
Gradient<vector3_type> gradient;
size_t I = S.I();
size_t J = S.J();
size_t K = S.K();
real_type dx = S.dx();
real_type dy = S.dy();
real_type dz = S.dz();
value_type zero = static_cast<value_type>(0.0);
grid_type F = S; //--- speed function
grid_type sign_phi; //--- sign function
compute_sign_function(phi,sign_phi);
iterator fbegin = F.begin();
index_iterator sbegin = S.begin();
index_iterator send = S.end();
size_t iteration = 0;
bool steady_state = false;
while (!steady_state)
{
value_type max_F = zero; //--- maximum speed, used to setup CFL condition
const_index_iterator p = phi.begin();
iterator s_phi = sign_phi.begin();
iterator f = fbegin;
index_iterator s = sbegin;
for(;s!=send; ++s,++f,++s_phi,++p)
{
size_t i = s.i();
size_t j = s.j();
size_t k = s.k();
vector3_type n = gradient(p);
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
size_t idx = ( k * J + j ) * I + i;
size_t idx_im1 = ( k * J + j ) * I + im1;
size_t idx_ip1 = ( k * J + j ) * I + ip1;
size_t idx_jm1 = ( k * J + jm1 ) * I + i;
size_t idx_jp1 = ( k * J + jp1 ) * I + i;
size_t idx_km1 = ( km1 * J + j ) * I + i;
size_t idx_kp1 = ( kp1 * J + j ) * I + i;
value_type s_idx = S(idx);
value_type s_idx_im1 = S(idx_im1);
value_type s_idx_ip1 = S(idx_ip1);
value_type s_idx_jm1 = S(idx_jm1);
value_type s_idx_jp1 = S(idx_jp1);
value_type s_idx_km1 = S(idx_km1);
value_type s_idx_kp1 = S(idx_kp1);
value_type Spx = (s_idx_ip1 - s_idx )/ dx;
value_type Spy = (s_idx_jp1 - s_idx )/ dy;
value_type Spz = (s_idx_kp1 - s_idx )/ dz;
value_type Smx = (s_idx - s_idx_im1)/ dx;
value_type Smy = (s_idx - s_idx_jm1)/ dy;
value_type Smz = (s_idx - s_idx_km1)/ dz;
*f = max( (*s_phi)*n(0) , zero)*Smx
+ min( (*s_phi)*n(0) , zero)*Spx
+ max( (*s_phi)*n(1) , zero)*Smy
+ min( (*s_phi)*n(1) , zero)*Spy
+ max( (*s_phi)*n(2) , zero)*Smz
+ min( (*s_phi)*n(2) , zero)*Spz;
max_F = max(max_F, fabs(*f));
}
value_type time_step = static_cast<value_type>( 1.0 / (max_F + 1.0) );
for(s=sbegin, f=fbegin;s!=send;++s,++f)
(*s) = (*s) - time_step * (*f);
++iteration;
if(iteration> max_iterations)
steady_state = true;
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_EXTRAPOLATION_H
#endif

View File

@@ -0,0 +1,292 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_FAST_BLUR_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_FAST_BLUR_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace grid
{
// The idea is to represent the blurred image as f(x,s) in terms of position
// x and scale s. Gaussian blurring is accomplished by using the input image
// I(x,s0) as the initial image (of scale s0 > 0) for the partial differential
// equation
// s*df/ds = s^2*Laplacian(f)
// where the Laplacian operator is
// Laplacian = (d/dx)^2, dimension 1
// Laplacian = (d/dx)^2+(d/dy)^2, dimension 2
// Laplacian = (d/dx)^2+(d/dy)^2+(d/dz)^2, dimension 3
//
// The term s*df/ds is approximated by
// s*df(x,s)/ds = (f(x,b*s)-f(x,s))/ln(b)
// for b > 1, but close to 1, where ln(b) is the natural logarithm of b. If
// you take the limit of the right-hand side as b approaches 1, you get the
// left-hand side.
//
// The term s^2*((d/dx)^2)f is approximated by
// s^2*((d/dx)^2)f = (f(x+h*s,s)-2*f(x,s)+f(x-h*s,s))/h^2
// for h > 0, but close to zero.
//
// Equating the approximations for the left-hand side and the right-hand side
// of the partial differential equation leads to the numerical method used in
// this code.
//
// For iterative application of these functions, the caller is responsible
// for constructing a geometric sequence of scales,
// s0, s1 = s0*b, s2 = s1*b = s0*b^2, ...
// where the base b satisfies 1 < b < exp(0.5*d) where d is the dimension of
// the image. The upper bound on b guarantees stability of the finite
// difference method used to approximate the partial differential equation.
// The method assumes a pixel size of h = 1.
//
//
// Sample usage:
//
// const int iterations = <number of passes to blur>;
// double scale = 1.0, log_base = 0.125, base = exp(0.125);
// grid_type tmp(); // Same dimensions as image!
// for (int i = 0; i < iterations; ++i, scale *= base)
// {
// fast_blur(image, tmp, scale, log_base);
// <use the blurred image aakImage here if desired>;
// }
//----------------------------------------------------------------------------
namespace detail
{
template <typename grid_type>
inline void fast_blur ( grid_type & image, grid_type & tmp, double si, double sj, double sk, double log_base)
{
using std::min;
using std::ceil;
using std::floor;
typedef typename grid_type::value_type value_type;
typedef typename grid_type::iterator iterator;
typedef typename grid_type::index_iterator index_iterator;
typedef typename grid_type::math_types math_types;
typedef typename math_types::real_type real_type;
size_t I = image.I();
size_t J = image.J();
size_t K = image.K();
index_iterator s = image.begin();
index_iterator s_end = image.end();
iterator t = tmp.begin();
for( ; s != s_end; ++s, ++t)
{
size_t i = s.i();
size_t j = s.j();
size_t k = s.k();
double dip = i + si;
double dim = i - si;
int ip = static_cast<int>( floor(dip) );
int im = static_cast<int>( ceil(dim) );
double djp = j + sj;
double djm = j - sj;
int jp = static_cast<int>( floor(djp) );
int jm = static_cast<int>( ceil(djm) );
double dkp = k + sk;
double dkm = k - sk;
int kp = static_cast<int>( floor(dkp) );
int km = static_cast<int>( ceil(dkm) );
im = ( i ) ? im : 0;
jm = ( j ) ? jm : 0;
km = ( k ) ? km : 0;
ip = min( ip, I - 1 );
jp = min( jp, J - 1 );
kp = min( kp, K - 1 );
//size_t idx = ( k * J + j ) * I + i;
size_t idx_im = ( k * J + j ) * I + im;
size_t idx_ip = ( k * J + j ) * I + ip;
size_t idx_jm = ( k * J + jm ) * I + i;
size_t idx_jp = ( k * J + jp ) * I + i;
size_t idx_km = ( km * J + j ) * I + i;
size_t idx_kp = ( kp * J + j ) * I + i;
real_type v000 = *s;
real_type vm00 = image(idx_im);
real_type vp00 = image(idx_ip);
real_type v0m0 = image(idx_jm);
real_type v0p0 = image(idx_jp);
real_type v00m = image(idx_km);
real_type v00p = image(idx_kp);
// i portion of second central difference
double isum = -2.0*v000 + vp00 + vm00;
if ( ip < I-1 ) // not on boundary, interpolate linearly
{
real_type vpp00 = image( (k*J+j)*I+(ip+1) );
isum += (dip-ip)*( vpp00 - vp00 );
}
if ( im > 0 ) // not on boundary, interpolate linearly
{
real_type vmm00 = image( (k*J+j)*I+(im-1) );
isum += (dim-im)*( vm00 - vmm00 );
}
// j portion of second central difference
double jsum = -2.0*v000 + v0p0 + v0m0;
if ( jp < J-1 ) // not on boundary, interpolate linearly
{
real_type v0pp0 = image( (k*J+(jp+1))*I+i );
jsum += (djp-jp)*( v0pp0 - v0p0 );
}
if ( jm > 0 ) // not on boundary, interpolate linearly
{
real_type v0mm0 = image( (k*J+(jm-1))*I+i );
jsum += (djm-jm)*( v0m0 - v0mm0 );
}
// k portion of second central difference
double ksum = -2.0*v000 + v00p + v00m;
if ( kp < K-1 ) // use boundary value
{
real_type v00pp = image( ((kp+1)*J+j)*I+i );
ksum += (dkp-kp)*( v00pp - v00p );
}
if ( km > 0 ) // use boundary value
{
real_type v00mm = image( ((km-1)*J+j)*I+i );
ksum += (dkm-km)*( v00m - v00mm );
}
*t = static_cast<value_type>(v000 + log_base*(isum+jsum+ksum));
}
image = tmp;
}
// for (k = 0; k < K; ++k)
// {
// double dkp = k + sk;
// double dkm = k - sk;
// int kp = static_cast<int>( floor(dkp) );
// int km = static_cast<int>( ceil(dkm) );
//
// for (j = 0; j < J; ++j)
// {
// double djp = j + sj;
// double djm = j - sj;
// int jp = static_cast<int>( floor(djp) );
// int jm = static_cast<int>( ceil(djm) );
//
// for (i = 0; i < I; ++i)
// {
// double dip = i + si;
// double dim = i - si;
// int ip = static_cast<int>( floor(dip) );
// int im = static_cast<int>( ceil(dim) );
//
// // i portion of second central difference
// double isum = -2.0*image(i,j,k);
// if ( ip >= I-1 ) // use boundary value
// {
// isum += image(I-1,j,k);
// }
// else // linearly interpolate
// {
// isum += image(ip,j,k)+(dip-ip)*(image(ip+1,j,k)-image(ip,j,k));
// }
//
// if ( im <= 0 ) // use boundary value
// {
// isum += image(0,j,k);
// }
// else // linearly interpolate
// {
// isum += image(im,j,k)+(dim-im)*(image(im,j,k)-image(im-1,j,k));
// }
//
// // j portion of second central difference
// double jsum = -2.0*image(i,j,k);
// if ( jp >= J-1 ) // use boundary value
// {
// jsum += image(i,J-1,k);
// }
// else // linearly interpolate
// {
// jsum += image(i,jp,k)+(djp-jp)*(image(i,jp+1,k)-image(i,jp,k));
// }
//
// if ( jm <= 0 ) // use boundary value
// {
// jsum += image(i,0,k);
// }
// else // linearly interpolate
// {
// jsum += image(i,jm,k)+(djm-jm)*(image(i,jm,k)-image(i,jm-1,k));
// }
//
// // k portion of second central difference
// double ksum = -2.0*image(i,j,k);
// if ( kp >= K-1 ) // use boundary value
// {
// ksum += image(i,j,K-1);
// }
// else // linearly interpolate
// {
// ksum += image(i,j,kp)+(dkp-kp)*(image(i,j,kp+1)-image(i,j,kp));
// }
//
// if ( km <= 0 ) // use boundary value
// {
// ksum += image(i,j,0);
// }
// else // linearly interpolate
// {
// ksum += image(i,j,km)+(dkm-km)*(image(i,j,km)-image(i,j,km-1));
// }
//
// tmp(i,j,k) = static_cast<value_type>(image(i,j,k) + log_base*(isum+jsum+ksum));
// }
// }
// }
// for (k = 0; k < K; ++k)
// {
// for (j = 0; j < J; ++j)
// {
// for (i = 0; i < I; ++i)
// image(i,j,k) = tmp(i,j,k);
// }
// }
} // namespace detail
template <typename grid_type>
inline void fast_blur ( grid_type & image, double sx, double sy, double sz, double log_base, size_t iterations)
{
using std::exp;
double base = exp(log_base);
grid_type tmp(image);
for( size_t i=0; i<iterations; ++i, sx*=base, sy*=base, sz*=base)
{
detail::fast_blur(image, tmp, sz, sy, sz, log_base);
}
}
template <typename grid_type>
inline void fast_blur ( grid_type & image, double s, double log_base, size_t iterations)
{
fast_blur(image, s, s, s, log_base, iterations);
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_FAST_BLUR_H
#endif

View File

@@ -0,0 +1,171 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_GRADIENT_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_GRADIENT_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace grid
{
template<typename grid_type, typename vector3_type>
inline void gradient(
grid_type const & grid
, size_t i
, size_t j
, size_t k
, vector3_type & gradient
)
{
using std::min;
typedef typename grid_type::value_type value_type;
typedef typename vector3_type::value_type real_type;
static value_type const unused = grid.unused();
size_t const & I = grid.I();
size_t const & J = grid.J();
size_t const & K = grid.K();
size_t im1 = 0, jm1 = 0, km1 = 0;
if ( i>0 )
im1 = i - 1;
if ( j>0 )
jm1 = j - 1;
if ( k>0 )
km1 = k - 1;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
size_t idx = ( k * J + j ) * I + i;
size_t idx_im1 = ( k * J + j ) * I + im1;
size_t idx_ip1 = ( k * J + j ) * I + ip1;
size_t idx_jm1 = ( k * J + jm1 ) * I + i;
size_t idx_jp1 = ( k * J + jp1 ) * I + i;
size_t idx_km1 = ( km1 * J + j ) * I + i;
size_t idx_kp1 = ( kp1 * J + j ) * I + i;
//--- Return Unused-vector if any of the values in the map is unused.
gradient = vector3_type(unused,unused,unused);
value_type s_idx = grid( idx );
if ( s_idx == unused )
return;
value_type s_im1 = grid( idx_im1 );
if ( s_im1 == unused )
return;
value_type s_ip1 = grid( idx_ip1 );
if ( s_ip1 == unused )
return;
value_type s_jm1 = grid( idx_jm1 );
if ( s_jm1 == unused )
return;
value_type s_jp1 = grid( idx_jp1 );
if ( s_jp1 == unused )
return;
value_type s_km1 = grid( idx_km1 );
if ( s_km1 == unused )
return;
value_type s_kp1 = grid( idx_kp1 );
if ( s_kp1 == unused )
return;
real_type r_idx = static_cast<real_type>( s_idx );
real_type r_im1 = static_cast<real_type>( s_im1 );
real_type r_ip1 = static_cast<real_type>( s_ip1 );
real_type r_jm1 = static_cast<real_type>( s_jm1 );
real_type r_jp1 = static_cast<real_type>( s_jp1 );
real_type r_km1 = static_cast<real_type>( s_km1 );
real_type r_kp1 = static_cast<real_type>( s_kp1 );
if ( i == 0 )
{
gradient( 0 ) = ( r_ip1 - r_idx );
gradient( 0 ) /= grid.dx();
}
else if ( i == ( grid.I() - 1 ) )
{
gradient( 0 ) = ( r_idx - r_im1 );
gradient( 0 ) /= grid.dx();
}
else
{
gradient( 0 ) = ( r_ip1 - r_im1 );
gradient( 0 ) /= ( 2 * grid.dx() );
}
if ( j == 0 )
{
gradient( 1 ) = ( r_jp1 - r_idx );
gradient( 1 ) /= grid.dy();
}
else if ( j == ( grid.J() - 1 ) )
{
gradient( 1 ) = ( r_idx - r_jm1 );
gradient( 1 ) /= grid.dy();
}
else
{
gradient( 1 ) = ( r_jp1 - r_jm1 );
gradient( 1 ) /= ( 2 * grid.dy() );
}
if ( k == 0 )
{
gradient( 2 ) = ( r_kp1 - r_idx );
gradient( 2 ) /= grid.dz();
}
else if ( k == ( grid.K() - 1 ) )
{
gradient( 2 ) = ( r_idx - r_km1 );
gradient( 2 ) /= grid.dz();
}
else
{
gradient( 2 ) = ( r_kp1 - r_km1 );
gradient( 2 ) /= ( 2 * grid.dz() );
}
}
template<typename grid_iterator,typename vector3_type>
inline void gradient (grid_iterator const & iter, vector3_type & gradient )
{
typedef typename grid_iterator::grid_type grid_type;
size_t i = iter.i();
size_t j = iter.j();
size_t k = iter.k();
grid_type const & grid = iter.get_grid();
gradient(grid, i, j, k, gradient);
}
template<typename grid_iterator>
inline typename grid_iterator::math_types::vector3_type gradient (grid_iterator const & iter )
{
typedef typename grid_iterator::math_types::vector3_type vector3_type;
vector3_type gradient;
gradient(iter, gradient);
return gradient;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_GRADIENT_H
#endif

View File

@@ -0,0 +1,70 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_GRADIENT_AT_POINT_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_GRADIENT_AT_POINT_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/math/math_trillinear.h>
#include <OpenTissue/core/containers/grid/util/grid_enclosing_indices.h>
#include <OpenTissue/core/containers/grid/util/grid_gradient.h>
namespace OpenTissue
{
namespace grid
{
template<typename grid_type,typename vector3_type>
inline vector3_type gradient_at_point (grid_type const & grid, vector3_type const & point )
{
typedef typename grid_type::value_type value_type;
const static value_type infty = grid.infinity();
const static value_type unused = grid.unused();
size_t i0, j0, k0, i1, j1, k1;
enclosing_indices(grid, point, i0, j0, k0, i1, j1, k1 );
vector3_type g000,g001,g010,g011,g100,g101,g110,g111;
gradient( grid, i0, j0, k0, g000 );
gradient( grid, i1, j0, k0, g001 );
gradient( grid, i0, j1, k0, g010 );
gradient( grid, i1, j1, k0, g011 );
gradient( grid, i0, j0, k1, g100 );
gradient( grid, i1, j0, k1, g101 );
gradient( grid, i0, j1, k1, g110 );
gradient( grid, i1, j1, k1, g111 );
if ( g000( 0 ) == unused )
return vector3_type( infty, infty, infty );
if ( g001( 0 ) == unused )
return vector3_type( infty, infty, infty );
if ( g010( 0 ) == unused )
return vector3_type( infty, infty, infty );
if ( g011( 0 ) == unused )
return vector3_type( infty, infty, infty );
if ( g100( 0 ) == unused )
return vector3_type( infty, infty, infty );
if ( g101( 0 ) == unused )
return vector3_type( infty, infty, infty );
if ( g110( 0 ) == unused )
return vector3_type( infty, infty, infty );
if ( g111( 0 ) == unused )
return vector3_type( infty, infty, infty );
typename vector3_type::value_type s = ( point(0) - ( i0*grid.dx() + grid.min_coord(0) ) ) / grid.dx();
typename vector3_type::value_type t = ( point(1) - ( j0*grid.dy() + grid.min_coord(1) ) ) / grid.dy();
typename vector3_type::value_type u = ( point(2) - ( k0*grid.dz() + grid.min_coord(2) ) ) / grid.dz();
return OpenTissue::math::trillinear(g000, g001, g010, g011, g100, g101, g110, g111, s, t, u ) ;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_GRADIENT_AT_POINT_H
#endif

View File

@@ -0,0 +1,69 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRADIENT_MAGNITUDE_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRADIENT_MAGNITUDE_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/grid_gradient.h>
#include <OpenTissue/core/math/math_vector3.h>
#include <cmath>
namespace OpenTissue
{
namespace grid
{
template<typename grid_type, typename real_type>
inline void gradient_magnitude(
grid_type const & grid
, size_t i
, size_t j
, size_t k
, real_type & grad_mag
)
{
using std::sqrt;
typedef OpenTissue::math::Vector3<real_type> vector3_type;
vector3_type g;
gradient(map,i,j,k,g);
grad_mag = sqrt(g*g);
}
template<typename grid_iterator, typename real_type>
inline void gradient_magnitude (grid_iterator const & iter, real_type & grad_mag )
{
typedef typename grid_iterator::grid_type grid_type;
size_t i = iter.i();
size_t j = iter.j();
size_t k = iter.k();
grid_type const & grid = iter.get_grid();
gradient_magnitude(grid, i, j, k, grad_mag);
}
template<typename grid_iterator>
inline typename grid_iterator::math_types::real_type gradient_magnitude( grid_iterator const & iter )
{
typedef typename grid_iterator::math_types::real_type real_type;
real_type grad_mag;
gradient_magnitude(iter, grad_mag);
return grad_mag;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRADIENT_MAGNITUDE_H
#endif

View File

@@ -0,0 +1,156 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_HESSIAN_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_HESSIAN_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace grid
{
template<typename grid_type, typename matrix3x3_type>
inline void hessian(
grid_type const & grid
, size_t i
, size_t j
, size_t k
, matrix3x3_type & H
)
{
using std::min;
typedef typename matrix3x3_type::value_type real_type;
static grid_type * old_grid = 0;
static real_type m_inv_dx2 = 0; ///< Pre-computed value of 1./grid.dx()*grid.dx()
static real_type m_inv_dy2 = 0; ///< Pre-computed value of 1./grid.dy()*grid.dy()
static real_type m_inv_dz2 = 0; ///< Pre-computed value of 1./grid.dz()*grid.dz()
static real_type m_inv_4dxy = 0; ///< Pre-computed value of 1./4*grid.dx()*grid.dy()
static real_type m_inv_4dxz = 0; ///< Pre-computed value of 1./4*grid.dx()*grid.dz()
static real_type m_inv_4dyz = 0; ///< Pre-computed value of 1./4*grid.dy()*grid.dz()
if(old_grid!=&grid)
{
old_grid = const_cast<grid_type*>(&grid);
m_inv_dx2 = 1.0 / grid.dx() * grid.dx();
m_inv_dy2 = 1.0 / grid.dy() * grid.dy();
m_inv_dz2 = 1.0 / grid.dz() * grid.dz();
m_inv_4dxy = 0.25 / grid.dx() * grid.dy();
m_inv_4dxz = 0.25 / grid.dx() * grid.dz();
m_inv_4dyz = 0.25 / grid.dy() * grid.dz();
}
size_t I = grid.I();
size_t J = grid.J();
size_t K = grid.K();
size_t im1 = 0, jm1 = 0, km1 = 0;
if ( i )
im1 = i - 1;
if ( j )
jm1 = j - 1;
if ( k )
km1 = k - 1;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
size_t idx_000 = ( k * J + j ) * I + i;
size_t idx_m00 = ( k * J + j ) * I + im1;
size_t idx_p00 = ( k * J + j ) * I + ip1;
size_t idx_0m0 = ( k * J + jm1 ) * I + i;
size_t idx_0p0 = ( k * J + jp1 ) * I + i;
size_t idx_00m = ( km1 * J + j ) * I + i;
size_t idx_00p = ( kp1 * J + j ) * I + i;
real_type d000 = 2.0 * grid( idx_000 );
real_type dp00 = grid( idx_p00 );
real_type dm00 = grid( idx_m00 );
real_type d0p0 = grid( idx_0p0 );
real_type d0m0 = grid( idx_0m0 );
real_type d00p = grid( idx_00p );
real_type d00m = grid( idx_00m );
size_t idx_pp0 = ( k * J + jp1 ) * I + ip1;
size_t idx_mp0 = ( k * J + jp1 ) * I + im1;
size_t idx_pm0 = ( k * J + jm1 ) * I + ip1;
size_t idx_mm0 = ( k * J + jm1 ) * I + im1;
size_t idx_p0p = ( kp1 * J + j ) * I + ip1;
size_t idx_m0p = ( kp1 * J + j ) * I + im1;
real_type dpp0 = grid( idx_pp0 );
real_type dmp0 = grid( idx_mp0 );
real_type dpm0 = grid( idx_pm0 );
real_type dmm0 = grid( idx_mm0 );
real_type dp0p = grid( idx_p0p );
real_type dm0p = grid( idx_m0p );
size_t idx_p0m = ( km1 * J + j ) * I + ip1;
size_t idx_m0m = ( km1 * J + j ) * I + im1;
size_t idx_0pp = ( kp1 * J + jp1 ) * I + i;
size_t idx_0pm = ( km1 * J + jp1 ) * I + i;
size_t idx_0mp = ( kp1 * J + jm1 ) * I + i;
size_t idx_0mm = ( km1 * J + jm1 ) * I + i;
real_type dp0m = grid( idx_p0m );
real_type dm0m = grid( idx_m0m );
real_type d0pp = grid( idx_0pp );
real_type d0pm = grid( idx_0pm );
real_type d0mp = grid( idx_0mp );
real_type d0mm = grid( idx_0mm );
//---- Hessian matrix is defines as
//
// | d/(dx*dx) d(/(dx*dy) d/(dx*dz) |
// H = | d/(dy*dx) d(/(dy*dy) d/(dy*dz) | phi
// | d/(dz*dx) d(/(dz*dy) d/(dz*dz) |
//
//
//--- Following is a central diff approximation
H( 0, 0 ) = ( dp00 + dm00 - d000 ) * m_inv_dx2;
H( 1, 1 ) = ( d0p0 + d0m0 - d000 ) * m_inv_dy2;
H( 2, 2 ) = ( d00p + d00m - d000 ) * m_inv_dz2;
H( 1, 0 ) = H( 0, 1 ) = ( dpp0 - dmp0 - dpm0 + dmm0 ) * m_inv_4dxy;
H( 0, 2 ) = H( 2, 0 ) = ( dp0p - dm0p - dp0m + dm0m ) * m_inv_4dxz;
H( 1, 2 ) = H( 2, 1 ) = ( d0pp - d0pm - d0mp + d0mm ) * m_inv_4dyz;
}
template<typename grid_iterator,typename matrix3x3_type>
inline void hessian (grid_iterator const & iter, matrix3x3_type & H )
{
typedef typename grid_iterator::grid_type grid_type;
size_t i = iter.i();
size_t j = iter.j();
size_t k = iter.k();
grid_type const & grid = iter.get_grid();
hessian(grid, i, j, k, H);
}
template<typename grid_iterator>
inline OpenTissue::math::Matrix3x3< typename grid_iterator::math_types::real_type >
hessian (grid_iterator const & iter )
{
typedef typename grid_iterator::math_types::real_type real_type;
typedef OpenTissue::math::Matrix3x3< real_type > matrix3x3_type;
matrix3x3_type H;
hessian(iter, H);
return H;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_HESSIAN_H
#endif

View File

@@ -0,0 +1,92 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_IDX_TO_COORD_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_IDX_TO_COORD_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cassert>
namespace OpenTissue
{
namespace grid
{
/**
* Index To Coordinate Conversion.
* This method computes the coordinates of the voxel with indices (i,j,k)
*
* @param map The grid.
* @param i The index of the voxel along the I-axe.
* @param j The index of the voxel along the J-axe.
* @param k The index of the voxel along the K-axe.
* @param point Upon return this parameter contains the coordinates.
*/
template <typename grid_type, typename vector3_type>
inline void idx2coord( grid_type const & grid, size_t i, size_t j, size_t k, vector3_type & point )
{
typedef typename vector3_type::value_type real_type;
assert(i<grid.I() || !"idx2coord(): i'th index was too big");
assert(j<grid.J() || !"idx2coord(): j'th index was too big");
assert(k<grid.K() || !"idx2coord(): k'th index was too big");
real_type const & dx = grid.dx();
real_type const & dy = grid.dy();
real_type const & dz = grid.dz();
real_type const & mx = grid.min_coord( 0 );
real_type const & my = grid.min_coord( 1 );
real_type const & mz = grid.min_coord( 2 );
point(0) = i * dx + mx;
point(1) = j * dy + my;
point(2) = k * dz + mz;
}
/**
* Index To Coordinate Conversion.
* This method computes the coordinates of the voxel with indices (i,j,k)
*
* @param iter An iterator to the voxel.
* @param point Upon return this parameter contains the coordinates.
*/
template<typename grid_iterator,typename vector3_type>
inline void idx2coord (grid_iterator const & iter, vector3_type & point )
{
typedef typename grid_iterator::grid_type grid_type;
size_t i = iter.i();
size_t j = iter.j();
size_t k = iter.k();
grid_type const & grid = iter.get_grid();
idx2coord(grid, i, j, k, point);
}
/**
* Index To Coordinate Conversion.
* This method computes the coordinates of the voxel with indices (i,j,k)
*
* @param iter An iterator to the voxel.
* @return Holds the coordinates.
*/
template<typename grid_iterator>
inline typename grid_iterator::math_types::vector3_type idx2coord (grid_iterator const & iter )
{
typedef typename grid_iterator::math_types::vector3_type vector3_type;
vector3_type point;
idx2coord(iter, point);
return point;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_IDX_TO_COORD_H
#endif

View File

@@ -0,0 +1,74 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_IGNORE_REGION_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_IGNORE_REGION_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace grid
{
/**
* Tag used to specify inside region of a level set (phi<0)
*/
struct inside_region_tag {};
/**
* Tag used to specify outside region of a level set (phi>0)
*/
struct outside_region_tag {};
/**
* Mask out inside region.
* This function masks out the inside region of level set
* function by assigning the unused value to all phi<0.
*
* @param phi The level set grid.
*/
template<typename grid_type>
inline void ignore_region(grid_type & phi, inside_region_tag const & /*region*/)
{
typedef typename grid_type::value_type value_type;
typedef typename grid_type::index_iterator iterator;
value_type unused = phi.unused();
iterator end = phi.end();
iterator p = phi.begin();
for(;p!=end;++p)
if(*p < 0 )
*p = unused;
}
/**
* Mask out outside region.
* This function masks out the inside region of level set
* function by assigning the unused value to all phi>0.
*
* @param phi The level set grid.
*/
template<typename grid_type>
inline void ignore_region(grid_type & phi, outside_region_tag const & /*region*/)
{
typedef typename grid_type::value_type value_type;
typedef typename grid_type::index_iterator iterator;
value_type unused = phi.unused();
iterator end = phi.end();
iterator p = phi.begin();
for(;p!=end;++p)
if(*p > 0 )
*p = unused;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_IGNORE_REGION_H
#endif

View File

@@ -0,0 +1,43 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_IS_POINT_INSIDE_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_IS_POINT_INSIDE_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace grid
{
/**
* Point Inclusion Test.
*
* Checks if a given points is strictly inside the grid.
* Notice if point lies on boundary of grid, then
* it is not consider to be inside the grid.
*
* @param point Vector with coordinates for a point.
* @return True if point is strictly inside. False otherwise.
*/
template<typename grid_type,typename vector3_type>
inline bool is_point_inside( grid_type const & grid, vector3_type const & point )
{
for ( size_t i = 0u;i < 3u;++i )
{
if ( point( i ) <= grid.min_coord( i ) )
return false;
if ( point( i ) >= grid.max_coord( i ) )
return false;
}
return true;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_IS_POINT_INSIDE_H
#endif

View File

@@ -0,0 +1,346 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_ITERATORS_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_ITERATORS_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <iterator>
namespace OpenTissue
{
namespace grid
{
namespace detail
{
//! basic iterator for walking through the WHOLE container
template <class grid_type_, class reference_type, class pointer_type>
class Iterator
: public std::iterator< std::random_access_iterator_tag, typename grid_type_::value_type >
{
public:
typedef grid_type_ grid_type;
typedef typename grid_type::math_types math_types;
private:
typedef OpenTissue::grid::detail::Iterator<grid_type, reference_type, pointer_type> self_type;
protected:
typedef typename grid_type::index_vector index_vector;
grid_type * m_grid;
pointer_type m_pos;
public:
grid_type & get_grid() { return *m_grid; }
grid_type const & get_grid() const { return *m_grid; }
pointer_type const & get_pointer() const { return m_pos; }
pointer_type & get_pointer() { return m_pos; }
public:
Iterator()
: m_grid( 0 )
, m_pos( 0 )
{}
Iterator( grid_type * grid, pointer_type pos )
: m_grid( grid )
, m_pos( pos )
{}
reference_type operator*()
{
return * m_pos;
}
self_type operator++( int )
{
self_type tmp = *this;
m_pos++;
return tmp;
}
self_type &operator++()
{
m_pos++;
return *this;
}
void operator+=( size_t m )
{
m_pos += m;
}
self_type operator+ ( size_t m )
{
self_type tmp = *this;
tmp.m_pos += m;
return tmp;
}
self_type operator- ( size_t m )
{
self_type tmp = *this;
tmp.m_pos -= m;
return tmp;
}
self_type operator--( int )
{
self_type tmp = *this;
m_pos--;
return tmp;
}
self_type &operator--()
{
m_pos--;
return *this;
}
void operator-=( size_t m ) { m_pos -= m; }
int operator- ( self_type const & other ) const { return m_pos -other.m_pos; }
bool operator< ( self_type const & other ) const { return m_pos < other.m_pos; }
bool operator<=( self_type const & other ) const { return m_pos <= other.m_pos; }
bool operator> ( self_type const & other ) const { return m_pos > other.m_pos; }
bool operator>=( self_type const & other ) const { return m_pos >= other.m_pos; }
// TODO: henrikd 2005-06-27 - confirm these!
index_vector compute_index() const
{
int offset = m_pos - m_grid->data();
index_vector res;
res(2) = offset / ( m_grid->J() * m_grid->I() );
offset = offset % ( m_grid->J() * m_grid->I() );
res(1) = offset / m_grid->I();
res(0) = offset % m_grid->I();
return res;
}
void operator+=( index_vector const & idx )
{
m_pos += idx(0) + m_grid->I() * idx(1) + m_grid->I() * m_grid->J() * idx(2);
}
self_type const & operator=( index_vector const & idx )
{
m_pos = m_grid->data() + idx(0) + m_grid->I() * idx(1) + m_grid->I() * m_grid->J() * idx(2);
return *this;
}
bool operator!=( self_type const & other )
{
return m_pos != other.m_pos;
}
bool operator==( self_type const & other )
{
return m_pos == other.m_pos;
}
};
//! iterator that keeps track of i,j,k position
/*! for walking through the WHOLE container */
template <class grid_type, class reference_type, class pointer_type>
class IndexIterator
: public OpenTissue::grid::detail::Iterator<grid_type, reference_type, pointer_type>
{
public:
typedef typename grid_type::math_types math_types;
protected:
typedef typename math_types::vector3_type vector3_type;
typedef typename math_types::index_vector3_type index_vector;
private:
typedef OpenTissue::grid::detail::Iterator<grid_type, reference_type, pointer_type> base_type;
typedef OpenTissue::grid::detail::IndexIterator<grid_type, reference_type, pointer_type> self_type;
// TODO: Use index_vector directly when vector is implemented as it should be!
size_t m_i;
size_t m_j;
size_t m_k;
static size_t const m_out_of_bounds = 0u - 1u;
void update_indices()
{
index_vector v = this->compute_index();
m_i = v(0);
m_j = v(1);
m_k = v(2);
}
public:
IndexIterator()
: base_type()
, m_i(0)
, m_j(0)
, m_k(0)
{}
IndexIterator( base_type const& other )
: base_type( other )
{
operator=( other );
}
IndexIterator( grid_type * grid, pointer_type pos )
: base_type( grid, pos )
{
// optionally move ijk if m_pos is not at begining of m_grid
if ( this->m_pos != this->m_grid->data() )
{
base_type::operator=( base_type( this->m_grid, this->m_pos ).compute_index() );
}
}
public:
size_t const& i() const { return m_i; }
size_t const& j() const { return m_j; }
size_t const& k() const { return m_k; }
index_vector get_index() const
{
return index_vector( m_i, m_j, m_k );
}
vector3_type get_coord() const
{
return vector3_type(
m_i * this->m_grid->dx() + this->m_grid->min_coord( 0 )
, m_j * this->m_grid->dy() + this->m_grid->min_coord( 1 )
, m_k * this->m_grid->dz() + this->m_grid->min_coord( 2 )
);
}
public:
self_type operator++( int )
{
self_type tmp = *this;
++( *this );
return tmp;
}
self_type &operator++()
{
++this->m_pos;
++m_i;
if ( m_i >= this->m_grid->I() )
{
m_i = 0u;
++m_j;
if ( m_j >= this->m_grid->J() )
{
m_j = 0u;
++m_k;
}
}
return *this;
}
self_type operator--( int )
{
self_type tmp = *this;
--( *this );
return tmp;
}
self_type &operator--()
{
--this->m_pos;
--m_i;
if ( m_i == m_out_of_bounds )
{
m_i = this->m_grid->I() - 1;
--m_j;
if ( m_j == m_out_of_bounds )
{
m_j = this->m_grid->J() - 1;
--m_k;
}
}
return *this;
}
// jump to new location
self_type const & operator=( index_vector const& idx )
{
m_i = idx(0);
m_j = idx(1);
m_k = idx(2);
this->m_pos = &( *this->m_grid ) ( idx );
return *this;
}
void operator+=( size_t m )
{
this->m_pos += m;
update_indices();
}
void operator-=( size_t m )
{
this->m_pos -= m;
update_indices();
}
self_type operator+ ( size_t m )
{
self_type tmp = *this;
tmp.m_pos += m;
tmp.update_indices();
return tmp;
}
self_type operator- ( size_t m )
{
self_type tmp = *this;
tmp.m_pos -= m;
tmp.update_indices();
return tmp;
}
self_type const & operator= ( base_type const & other )
{
this->m_grid = const_cast<grid_type*>( &( other.get_grid() ) );
this->m_pos = other.get_pointer();
if ( this->m_pos == this->m_grid->data() )
{
m_i = 0u;
m_j = 0u;
m_k = 0u;
}
else
{
update_indices();
}
return *this;
}
};
} // namespace detail
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_ITERATORS_H
#endif

View File

@@ -0,0 +1,532 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_JUNCTIONS_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_JUNCTIONS_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/math/math_basic_types.h> // Needed for BasicMathTypes
#include <OpenTissue/core/containers/grid/util/grid_gradient.h>
#include <OpenTissue/core/containers/grid/util/grid_coord2idx.h>
#include <OpenTissue/core/containers/grid/util/grid_idx2coord.h>
#include <OpenTissue/core/containers/grid/util/grid_gradient_at_point.h>
#include <OpenTissue/core/containers/grid/util/grid_local_minima.h>
#include <OpenTissue/core/containers/grid/util/grid_aof.h>
#include <OpenTissue/collision/spatial_hashing/spatial_hashing.h>
#include <OpenTissue/collision/intersect/intersect_sphere_triangle.h>
#include <cmath>
#include <list>
namespace OpenTissue
{
namespace grid
{
namespace detail
{
template<typename math_types_>
class JunctionCandidate
{
public:
typedef math_types_ math_types;
typedef typename math_types::vector3_type vector3_type;
typedef typename math_types::real_type real_type;
public:
vector3_type m_center; //--- Estimated center of the largest enclosing sphere.
real_type m_radius; //--- Upper estimate of the radius of the largest enclosed sphere located at the junction point.
size_t m_cnt_boundary; //--- number of boundary that the largest enclosed sphere touches.
public:
JunctionCandidate(vector3_type const & center, real_type const & radius)
: m_center(center)
, m_radius(radius)
, m_cnt_boundary()
{
assert(m_radius>0 || !"JunctionCandidate(): Non-positive radius");
}
};
template<typename face_type,typename junction_candiate_type>
class JunctionCollisionPolicy
{
public:
typedef typename junction_candiate_type::math_types math_types;
typedef typename math_types::vector3_type vector3_type;
typedef typename math_types::real_type real_type;
typedef face_type data_type;
typedef junction_candiate_type query_type;
typedef bool result_container;
typedef OpenTissue::spatial_hashing::PrimeNumberHashFunction hash_function;
typedef OpenTissue::spatial_hashing::Grid< vector3_type, OpenTissue::math::Vector3<int>, data_type, hash_function> hash_grid;
public:
vector3_type min_coord(face_type const & face) const
{
vector3_type coord;
mesh::compute_face_minimum_coord(face,coord);
return coord;
}
vector3_type max_coord(face_type const & face) const
{
vector3_type coord;
mesh::compute_face_maximum_coord(face,coord);
return coord;
}
vector3_type min_coord(junction_candiate_type const & candidate) const
{
return vector3_type(
candidate.m_center(0) - candidate.m_radius
, candidate.m_center(1) - candidate.m_radius
, candidate.m_center(2) - candidate.m_radius
);
}
vector3_type max_coord(junction_candiate_type const & candidate) const
{
return vector3_type(
candidate.m_center(0) + candidate.m_radius
, candidate.m_center(1) + candidate.m_radius
, candidate.m_center(2) + candidate.m_radius
);
}
void reset(result_container & /*results*/) { }
void report(data_type const & data, query_type const & query,result_container & /*results*/)
{
face_type * face = const_cast<face_type*>(&data);
junction_candiate_type * candidate = const_cast<junction_candiate_type*>(&query);
if(candidate->m_cnt_boundary >= 4)
return;
OpenTissue::geometry::Triangle<math_types> triangle;
triangle.set( face );
typedef OpenTissue::math::BasicMathTypes< real_type, size_t> math_types;
OpenTissue::geometry::Sphere<math_types> sphere(candidate->m_center,candidate->m_radius);
if(OpenTissue::intersect::sphere_triangle(sphere,triangle))
{
++(candidate->m_cnt_boundary);
}
}
};
}// namespace detail
/**
* Detect MREP junctions.
*
* KE 2006-02-15: This is work in progress, please ignore it!
*
* @param aof A the aof grid.
* @param F A grid containing non-zero values for junctions.
*/
template<typename grid_type, typename mesh_type, typename point_container >
inline void junctions(
grid_type const & aof
, grid_type & phi
, mesh_type /*const*/ & mesh
, point_container & points
)
{
using std::fabs;
using std::min;
using std::max;
using std::sqrt;
typedef typename point_container::value_type vector3_type;
typedef typename vector3_type::value_type real_type;
typedef typename grid_type::value_type value_type;
typedef typename grid_type::const_iterator const_iterator;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename grid_type::index_iterator index_iterator;
typedef typename mesh_type::face_type face_type;
//--- vorticity w = grad cross grad(phi) Is this any good????
//
// d gz d gy
// wx = ------ - ------
// dy dz
//
// d gx d gz
// wy = ------ - ------
// dz dx
//
// d gy d gx
// wy = ------ - ------
// dx dy
//
//{
//-------------------------------------------------------
//--- Thining based detection, sucks!!! ----------------
//-------------------------------------------------------
//size_t I = phi.I();
//size_t J = phi.J();
//size_t K = phi.K();
//value_type s[27];
//grid_type tmp = aof;
//{
// index_iterator t = tmp.begin();
// const_index_iterator a = aof.begin();
// const_index_iterator end = aof.end();
// for(;a!=end;++a,++t)
// {
// (*t) = 0;
// size_t i = a.i();
// size_t j = a.j();
// size_t k = a.k();
// if( (*a) > 0)
// (*t) = detail::compute_aof_value(phi,i,j,k,0.1);
// if( (*t) < 1e-5)
// {
// (*t) = 0;
// continue;
// }
// if( phi(i,j,k) > 0)
// {
// (*t) = 0;
// continue;
// }
// }
//}
//{
// phi = tmp;
// index_iterator t = phi.begin();
// index_iterator a = tmp.begin();
// index_iterator end = tmp.end();
// for(;a!=end;++a,++t)
// {
// size_t i = a.i();
// size_t j = a.j();
// size_t k = a.k();
// if( (*a) < 1e-5)
// continue;
// size_t im1 = ( i ) ? i - 1 : 0;
// size_t jm1 = ( j ) ? j - 1 : 0;
// size_t km1 = ( k ) ? k - 1 : 0;
// size_t ip1 = min( i + 1u, I - 1u );
// size_t jp1 = min( j + 1u, J - 1u );
// size_t kp1 = min( k + 1u, K - 1u );
// s[0] = tmp( im1, jm1, km1);
// s[1] = tmp( im1, jm1, k);
// s[2] = tmp( im1, jm1, kp1);
// s[3] = tmp( im1, j, km1);
// s[4] = tmp( im1, j, k);
// s[5] = tmp( im1, j, kp1);
// s[6] = tmp( im1, jp1, km1);
// s[7] = tmp( im1, jp1, k);
// s[8] = tmp( im1, jp1, kp1);
// s[9] = tmp( i, jm1, km1);
// s[10] = tmp( i, jm1, k);
// s[11] = tmp( i, jm1, kp1);
// s[12] = tmp( i, j, km1);
// s[13] = tmp( i, j, k);
// s[14] = tmp( i, j, kp1);
// s[15] = tmp( i, jp1, km1);
// s[16] = tmp( i, jp1, k);
// s[17] = tmp( i, jp1, kp1);
// s[18] = tmp( ip1, jm1, km1);
// s[19] = tmp( ip1, jm1, k);
// s[20] = tmp( ip1, jm1, kp1);
// s[21] = tmp( ip1, j, km1);
// s[22] = tmp( ip1, j, k);
// s[23] = tmp( ip1, j, kp1);
// s[24] = tmp( ip1, jp1, km1);
// s[25] = tmp( ip1, jp1, k);
// s[26] = tmp( ip1, jp1, kp1);
// bool has_zero_neighbor = false;
// bool has_larger_neighbor = false;
// bool is_maxima = true;
// for(size_t i=0u;i<27u;++i)
// {
// if(s[i]<=0)
// has_zero_neighbor = true;
// if(s[i]>s[13])
// has_larger_neighbor = true;
// if(i!=13 && s[13]< s[i])
// is_maxima = false;
// }
// if(!is_maxima && has_larger_neighbor && has_zero_neighbor)//--- thining
// {
// (*t) = 0;
// continue;
// }
// vector3_type p;
// idx2coord(aof, i, j, k, p);
// points.push_back(p);
// }
//}
//-------------------------------------------------------
//--- Angle based detection, sucks!!! -------------------
//-------------------------------------------------------
//vector3_type g[27];
//vector3_type p[27];
//value_type s[27];
//vector3_type d[27];
//vector3_type q[27];
//size_t I = phi.I();
//size_t J = phi.J();
//size_t K = phi.K();
// const_index_iterator a = aof.begin();
// const_index_iterator end = aof.end();
// for(;a!=end;++a,++t)
// {
// size_t i = a.i();
// size_t j = a.j();
// size_t k = a.k();
// if( (*a) < 1e-5) || phi(i,j,k) > 0)
// {
// continue;
// }
//size_t im1 = ( i ) ? i - 1 : 0;
//size_t jm1 = ( j ) ? j - 1 : 0;
//size_t km1 = ( k ) ? k - 1 : 0;
//size_t ip1 = min( i + 1u, I - 1u );
//size_t jp1 = min( j + 1u, J - 1u );
//size_t kp1 = min( k + 1u, K - 1u );
//grid_gradient(phi, im1, jm1, km1, g[0]);
//grid_gradient(phi, im1, jm1, k, g[1]);
//grid_gradient(phi, im1, jm1, kp1, g[2]);
//grid_gradient(phi, im1, j, km1, g[3]);
//grid_gradient(phi, im1, j, k, g[4]);
//grid_gradient(phi, im1, j, kp1, g[5]);
//grid_gradient(phi, im1, jp1, km1, g[6]);
//grid_gradient(phi, im1, jp1, k, g[7]);
//grid_gradient(phi, im1, jp1, kp1, g[8]);
//grid_gradient(phi, i, jm1, km1, g[9]);
//grid_gradient(phi, i, jm1, k, g[10]);
//grid_gradient(phi, i, jm1, kp1, g[11]);
//grid_gradient(phi, i, j, km1, g[12]);
//grid_gradient(phi, i, j, k, g[13]);
//grid_gradient(phi, i, j, kp1, g[14]);
//grid_gradient(phi, i, jp1, km1, g[15]);
//grid_gradient(phi, i, jp1, k, g[16]);
//grid_gradient(phi, i, jp1, kp1, g[17]);
//grid_gradient(phi, ip1, jm1, km1, g[18]);
//grid_gradient(phi, ip1, jm1, k, g[19]);
//grid_gradient(phi, ip1, jm1, kp1, g[20]);
//grid_gradient(phi, ip1, j, km1, g[21]);
//grid_gradient(phi, ip1, j, k, g[22]);
//grid_gradient(phi, ip1, j, kp1, g[23]);
//grid_gradient(phi, ip1, jp1, km1, g[24]);
//grid_gradient(phi, ip1, jp1, k, g[25]);
//grid_gradient(phi, ip1, jp1, kp1, g[26]);
//grid_idx2coord(phi, im1, jm1, km1, p[0]);
//grid_idx2coord(phi, im1, jm1, k, p[1]);
//grid_idx2coord(phi, im1, jm1, kp1, p[2]);
//grid_idx2coord(phi, im1, j, km1, p[3]);
//grid_idx2coord(phi, im1, j, k, p[4]);
//grid_idx2coord(phi, im1, j, kp1, p[5]);
//grid_idx2coord(phi, im1, jp1, km1, p[6]);
//grid_idx2coord(phi, im1, jp1, k, p[7]);
//grid_idx2coord(phi, im1, jp1, kp1, p[8]);
//grid_idx2coord(phi, i, jm1, km1, p[9]);
//grid_idx2coord(phi, i, jm1, k, p[10]);
//grid_idx2coord(phi, i, jm1, kp1, p[11]);
//grid_idx2coord(phi, i, j, km1, p[12]);
//grid_idx2coord(phi, i, j, k, p[13]);
//grid_idx2coord(phi, i, j, kp1, p[14]);
//grid_idx2coord(phi, i, jp1, km1, p[15]);
//grid_idx2coord(phi, i, jp1, k, p[16]);
//grid_idx2coord(phi, i, jp1, kp1, p[17]);
//grid_idx2coord(phi, ip1, jm1, km1, p[18]);
//grid_idx2coord(phi, ip1, jm1, k, p[19]);
//grid_idx2coord(phi, ip1, jm1, kp1, p[20]);
//grid_idx2coord(phi, ip1, j, km1, p[21]);
//grid_idx2coord(phi, ip1, j, k, p[22]);
//grid_idx2coord(phi, ip1, j, kp1, p[23]);
//grid_idx2coord(phi, ip1, jp1, km1, p[24]);
//grid_idx2coord(phi, ip1, jp1, k, p[25]);
//grid_idx2coord(phi, ip1, jp1, kp1, p[26]);
//s[0] = phi( im1, jm1, km1);
//s[1] = phi( im1, jm1, k);
//s[2] = phi( im1, jm1, kp1);
//s[3] = phi( im1, j, km1);
//s[4] = phi( im1, j, k);
//s[5] = phi( im1, j, kp1);
//s[6] = phi( im1, jp1, km1);
//s[7] = phi( im1, jp1, k);
//s[8] = phi( im1, jp1, kp1);
//s[9] = phi( i, jm1, km1);
//s[10] = phi( i, jm1, k);
//s[11] = phi( i, jm1, kp1);
//s[12] = phi( i, j, km1);
//s[13] = phi( i, j, k);
//s[14] = phi( i, j, kp1);
//s[15] = phi( i, jp1, km1);
//s[16] = phi( i, jp1, k);
//s[17] = phi( i, jp1, kp1);
//s[18] = phi( ip1, jm1, km1);
//s[19] = phi( ip1, jm1, k);
//s[20] = phi( ip1, jm1, kp1);
//s[21] = phi( ip1, j, km1);
//s[22] = phi( ip1, j, k);
//s[23] = phi( ip1, j, kp1);
//s[24] = phi( ip1, jp1, km1);
//s[25] = phi( ip1, jp1, k);
//s[26] = phi( ip1, jp1, kp1);
//for(size_t i=0u;i<27u;++i)
//{
// q[i] = p[i] - g[i]*s[i];
// d[i] = q[i] - p[i];
//}
//bool is_junction = false;
//real_type min_cos_theta = 100000.0;
//real_type max_cos_theta = 0.0;
//for(size_t i=0u;i<27u;++i)
//{
// if(i==13)
// continue;
// for(size_t j=i+1;j<27u;++j)
// {
// if(j==13)
// continue;
// real_type cos_theta = fabs( g[i] * g[j] );
// cos_theta = max(0.0, min(cos_theta, 1.0));
// min_cos_theta = min(cos_theta,min_cos_theta);
// max_cos_theta = max(cos_theta,max_cos_theta);
// }
//}
//std::cout << min_cos_theta << " " << max_cos_theta << std::endl;
//if(min_cos_theta >0.01 && min_cos_theta< 0.99)
// is_junction = true;
//if(is_junction)
//points.push_back(p[13]);
// }
//-------------------------------------------------------
//-------------------------------------------------------
//-------------------------------------------------------
std::cout << "junctions(): junction candiates = " << points.size() << std::endl;
}
template<typename grid_type, typename mesh_type, typename point_container >
inline void junctions2(
grid_type const & aof
, grid_type const & phi
, mesh_type /*const*/ & mesh
, point_container & points
)
{
//--- For each point in the clamped AOF take a sphere with radius
//--- equal to the distance value plus some small threshold (voxel size!), test
//--- the sphere for intersection with the mesh-faces
//---
//--- If at least four intersection points are found, then the AOF point is a potential junction... no! Think of a pyramid
//---
//--- At least four points is necessary but not a sufficient condition...
//---
//--- For each intersection take a vector from the AOF point to the face intersection point, if all such vectors
//--- contrain the sphere then we have a junction point. That is the vectors must span the entire R^3 (to remove
//--- 3DOF of translation motion of the sphere along the mrep).
//---
//--- Do we need sub-pixel precision of AOF points?......
//---
//---
//---
//--- culver : exact polyhedra
//--- foskey : theta-SMA
//--- hoffmann: voronoi-region/distance map
//---
//---
//---
//---
using std::fabs;
using std::min;
using std::sqrt;
typedef typename point_container::value_type vector3_type;
typedef typename vector3_type::value_type real_type;
typedef typename grid_type::const_iterator const_iterator;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename grid_type::math_types math_types;
typedef typename mesh_type::face_type face_type;
typedef detail::JunctionCandidate<math_types> candidate_type;
typedef std::list<candidate_type> candidate_container;
typedef detail::JunctionCollisionPolicy<face_type,candidate_type> collision_policy;
typedef AABBDataQuery< typename collision_policy::hash_grid, collision_policy > query_algorithm;
bool results = false;
query_algorithm query;
candidate_container candidates;
{
real_type dx = phi.dx()*0.5;
real_type dy = phi.dy()*0.5;
real_type dz = phi.dz()*0.5;
real_type rho = sqrt(dx*dx+dy*dy+dz*dz)*.5;
const_iterator p = phi.begin();
const_index_iterator a = aof.begin();
const_index_iterator end = aof.end();
for(;a!=end;++a,++p)
{
if( (*a) < 1e-5 || (*p) >= 0)
continue;
vector3_type center;
idx2coord(a,center);
real_type radius = fabs( *p );
candidate_type candidate(center,radius + rho);
candidates.push_back(candidate);
}
}
query.init(candidates.begin(),candidates.end());
query(mesh.face_begin(), mesh.face_end(), candidates.begin(), candidates.end(), results, typename query_algorithm::all_tag() );
size_t cnt = 0;
for(typename candidate_container::iterator c = candidates.begin(); c!=candidates.end();++c)
{
if(c->m_cnt_boundary >= 4)
{
points.push_back(c->m_center );
++cnt;
}
}
std::cout << "junctions2(): junction candiates = " << cnt << std::endl;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_JUNCTIONS_H
#endif

View File

@@ -0,0 +1,160 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_LOCAL_MINIMA_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_LOCAL_MINIMA_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/grid_idx2coord.h>
#include <cmath>
namespace OpenTissue
{
namespace grid
{
namespace detail
{
/**
* Test if a specified node is a strict local minima.
*
* @param i
* @param j
* @param k
* @param phi
*
* @return True if node i,j,k is a local minima, otherwise false.
*/
template < typename grid_type >
inline bool is_local_minima(
size_t i
, size_t j
, size_t k
, grid_type const & phi
)
{
using std::min;
static size_t idx[27];
size_t I = phi.I();
size_t J = phi.J();
size_t K = phi.K();
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
idx[0] = ( kp1 * J + jp1 ) * I + im1;
idx[1] = ( k * J + jp1 ) * I + im1;
idx[2] = ( km1 * J + jp1 ) * I + im1;
idx[3] = ( kp1 * J + j ) * I + im1;
idx[4] = ( k * J + j ) * I + im1;
idx[5] = ( km1 * J + j ) * I + im1;
idx[6] = ( kp1 * J + jm1 ) * I + im1;
idx[7] = ( k * J + jm1 ) * I + im1;
idx[8] = ( km1 * J + jm1 ) * I + im1;
idx[9] = ( kp1 * J + jp1 ) * I + i;
idx[10] = ( k * J + jp1 ) * I + i;
idx[11] = ( km1 * J + jp1 ) * I + i;
idx[12] = ( kp1 * J + j ) * I + i;
idx[13] = ( k * J + j ) * I + i;
idx[14] = ( km1 * J + j ) * I + i;
idx[15] = ( kp1 * J + jm1 ) * I + i;
idx[16] = ( k * J + jm1 ) * I + i;
idx[17] = ( km1 * J + jm1 ) * I + i;
idx[18] = ( kp1 * J + jp1 ) * I + ip1;
idx[19] = ( k * J + jp1 ) * I + ip1;
idx[20] = ( km1 * J + jp1 ) * I + ip1;
idx[21] = ( kp1 * J + j ) * I + ip1;
idx[22] = ( k * J + j ) * I + ip1;
idx[23] = ( km1 * J + j ) * I + ip1;
idx[24] = ( kp1 * J + jm1 ) * I + ip1;
idx[25] = ( k * J + jm1 ) * I + ip1;
idx[26] = ( km1 * J + jm1 ) * I + ip1;
for(size_t i=0;i<27u;++i)
if( phi(idx[13]) > phi(idx[i]) )
return false;
return true;
}
} // namespace detail
/**
* Extract local minima nodes.
* Note that local minima may exist at non-nodal locations. This function
* only considers nodal positions. Thus if you are looking for local minima
* at sub-pixel accuracy, then you need another approach.
*
* @param phi The map from where local minima nodes should be extracted from.
* @param points Upon return this container contains all the coordinates of all nodes that where local minima.
*/
template < typename grid_type,typename point_container >
inline void local_minima_as_points(
grid_type const & phi
, point_container & points
)
{
typedef typename point_container::value_type vector3_type;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename vector3_type::value_type real_type;
typedef typename grid_type::value_type value_type;
const_index_iterator pend = phi.end();
const_index_iterator p = phi.begin();
for(;p!=pend;++p)
{
if(detail::is_local_minima(p.i(),p.j(),p.k(),phi))
{
vector3_type point;
idx2coord(phi,p.i(),p.j(),p.k(),point);
points.push_back(point);
}
}
}
/**
* Extract Local Minima as Points.
*
* @param phi
* @param mask A mask that can be used to mask-out nodes in phi, which is not
* of interest. Positive values correspond to nodes that are allowed
* to be classified as local minima.
* @param points
*/
template < typename grid_type,typename point_container >
inline void local_minima_as_points(
grid_type const & phi
, grid_type const & mask
, point_container & points
)
{
typedef typename point_container::value_type vector3_type;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename vector3_type::value_type real_type;
typedef typename grid_type::value_type value_type;
const_index_iterator end = phi.end();
const_index_iterator p = phi.begin();
const_index_iterator m = mask.begin();
for(;p!=end;++p,++m)
{
if( (*m) <= 0 )
continue;
if(detail::is_local_minima(p.i(),p.j(),p.k(),phi))
{
vector3_type point;
idx2coord(phi,p.i(),p.j(),p.k(),point);
points.push_back(point);
}
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_LOCAL_MINIMA_H
#endif

View File

@@ -0,0 +1,94 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_MEAN_CURVATURE_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_MEAN_CURVATURE_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
#include <OpenTissue/core/containers/grid/util/grid_gradient.h>
#include <OpenTissue/core/containers/grid/util/grid_hessian.h>
namespace OpenTissue
{
namespace grid
{
template<typename grid_type, typename real_type>
inline void mean_curvature(
grid_type const & grid
, size_t i
, size_t j
, size_t k
, real_type & K
)
{
using std::min;
using std::max;
using std::pow;
typedef OpenTissue::math::Vector3<real_type> vector3_type;
typedef OpenTissue::math::Matrix3x3<real_type> matrix3x3_type;
real_type limit_K = boost::numeric_cast<real_type>( 1. / min( grid.dx(), min( grid.dy(), grid.dz() ) ) );
vector3_type g;
matrix3x3_type H;
gradient( grid, i, j, k, g );
hessian( grid, i, j, k, H );
real_type h = g * g;
//--- Test whether the gradient was zero, if so we simply imagine it has norm one, a better
//--- solution would proberly be to pick a random node and compute the curvature information
//--- herein (this is suggest by Oscher and Fedkiw).
if ( h == 0 )
h = 1;
//--- Compute Mean curvature, defined as: kappa = \nabla \cdot (\nabla \phi / \norm{\nabla \phi} )
const static real_type exponent = boost::numeric_cast<real_type>( 3. / 2. );
K = ( 1.0 / pow( h, exponent ) ) * (
g( 0 ) * g( 0 ) * ( H( 1, 1 ) + H( 2, 2 ) ) - 2. * g( 1 ) * g( 2 ) * H( 1, 2 ) +
g( 1 ) * g( 1 ) * ( H( 0, 0 ) + H( 2, 2 ) ) - 2. * g( 0 ) * g( 2 ) * H( 0, 2 ) +
g( 2 ) * g( 2 ) * ( H( 0, 0 ) + H( 1, 1 ) ) - 2. * g( 0 ) * g( 1 ) * H( 0, 1 )
);
//--- Clamp Curvature, it does not make sense if we compute
//--- a curvature value that can not be representated with the
//--- current map resolution.
K = min( K, limit_K );
K = max( K, -limit_K );
}
template<typename grid_iterator,typename real_type>
inline void mean_curvature (grid_iterator const & iter, real_type & K)
{
typedef typename grid_iterator::grid_type grid_type;
size_t i = iter.i();
size_t j = iter.j();
size_t k = iter.k();
grid_type const & grid = iter.get_grid();
mean_curvature(grid, i, j, k, K);
}
template<typename grid_iterator>
inline typename grid_iterator::math_types::real_type mean_curvature( grid_iterator const & iter )
{
typedef typename grid_iterator::math_types::real_type real_type;
real_type K;
mean_curvature(iter, K);
return K;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_MEAN_CURVATURE_H
#endif

View File

@@ -0,0 +1,239 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_METAMORPHOSIS_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_METAMORPHOSIS_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace grid
{
/**
* Auxilliary function used by metamorphosis().
*
* This function compute the normal velocity flow.
*
*
*
* @param phi The current surface
* @param gamma The inside-outside function of target surface
* @param F Upon return contains the normal velocity flow field.
*/
template<
typename grid_type
>
inline void metamorphosis_speed_function(
grid_type const & phi
, grid_type const & gamma
, grid_type & F
)
{
using std::min;
using std::max;
using std::sqrt;
typedef typename grid_type::value_type value_type;
typedef typename grid_type::iterator iterator;
typedef typename grid_type::index_iterator index_iterator;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename grid_type::math_types math_types;
typedef typename math_types::real_type real_type;
size_t I = phi.I();
size_t J = phi.J();
size_t K = phi.K();
real_type dx = phi.dx();
real_type dy = phi.dy();
real_type dz = phi.dz();
const_index_iterator end = phi.end();
const_index_iterator u = phi.begin();
index_iterator f = F.begin();
const_index_iterator g = gamma.begin();
for(;u!=end; ++u,++g,++f)
{
size_t i = u.i();
size_t j = u.j();
size_t k = u.k();
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
size_t idx = ( k * J + j ) * I + i;
size_t idx_im1 = ( k * J + j ) * I + im1;
size_t idx_ip1 = ( k * J + j ) * I + ip1;
size_t idx_jm1 = ( k * J + jm1 ) * I + i;
size_t idx_jp1 = ( k * J + jp1 ) * I + i;
size_t idx_km1 = ( km1 * J + j ) * I + i;
size_t idx_kp1 = ( kp1 * J + j ) * I + i;
real_type u_idx = phi(idx);
real_type u_idx_im1 = phi(idx_im1);
real_type u_idx_ip1 = phi(idx_ip1);
real_type u_idx_jm1 = phi(idx_jm1);
real_type u_idx_jp1 = phi(idx_jp1);
real_type u_idx_km1 = phi(idx_km1);
real_type u_idx_kp1 = phi(idx_kp1);
real_type Upx = (u_idx_ip1 - u_idx )/ dx;
real_type Upy = (u_idx_jp1 - u_idx )/ dy;
real_type Upz = (u_idx_kp1 - u_idx )/ dz;
real_type Umx = (u_idx - u_idx_im1)/ dx;
real_type Umy = (u_idx - u_idx_jm1)/ dy;
real_type Umz = (u_idx - u_idx_km1)/ dz;
real_type Upx_min = min( Upx, 0.0);
real_type Upx_max = max( Upx, 0.0);
real_type Umx_min = min( Umx, 0.0);
real_type Umx_max = max( Umx, 0.0);
real_type Upy_min = min( Upy, 0.0);
real_type Upy_max = max( Upy, 0.0);
real_type Umy_min = min( Umy, 0.0);
real_type Umy_max = max( Umy, 0.0);
real_type Upz_min = min( Upz, 0.0);
real_type Upz_max = max( Upz, 0.0);
real_type Umz_min = min( Umz, 0.0);
real_type Umz_max = max( Umz, 0.0);
if(-(*g)>=0)
*f = (*g)*sqrt(
Upx_min*Upx_min
+ Umx_max*Umx_max
+ Upy_min*Upy_min
+ Umy_max*Umy_max
+ Upz_min*Upz_min
+ Umz_max*Umz_max
);
else
*f = (*g)*sqrt(
Upx_max*Upx_max
+ Umx_min*Umx_min
+ Upy_max*Upy_max
+ Umy_min*Umy_min
+ Upz_max*Upz_max
+ Umz_min*Umz_min
);
}
//std::cout << "metamorphosis_speed_function(): done..." << std::endl;
}
/**
* Solid Shape Metamorphosis.
*
* Solve the PDE:
*
* \frac{\partial \phi(x) }{ \partial t} = | \nabla \phi(x)| \gamma(x)
*
* where \gamma usually is an inside-outside function of the target
* object. Usually the signed distance map of the target is used as
* \gamma. That is
*
* \gamma (x) = \phi_target (x)
*
* It could be defined more genrally as
*
* \gamma (x) = f ( \phi_target (x) )
*
* where the function f is used to control the speed of the moving
* interface of phi.
*
*
* The process is controlled by the user by defining the initial overlapping
* regions of source and target.
*
*
* The final metamorphosis strategy is
*
* \frac{\partial \phi(x) }{ \partial t} = | \nabla \phi(x)| \gamma( T(x,alpha) )
*
* Given the coordinate transform:
*
* y = T(x,alpha)
*
* where x is a point in source and y is corresponding point in
* target, and 0 \leq alpha \leq 1 is a parameterization such that
*
* T(x,0) = x
* T(x,1) = y
*
* The transform T is for instance useful for alignment of the objects.
*
*
* The flow is implemented using a upwind (Godonov) scheme. Currently
* implementation do not support the T-transform. The user do have the
* option of applying an f-function outside the function, since only
* the gamma-field is surplied to this function.
*
*
* @param phi Input/output level set.
* @param gamma The inside/outside function of the target object.
* @param dt The time-step size.
*/
template<
typename grid_type
>
inline void metamorphosis(
grid_type & phi
, grid_type const & gamma
, typename grid_type::math_types::real_type const & dt
)
{
typedef typename grid_type::value_type value_type;
typedef typename grid_type::iterator iterator;
typedef typename grid_type::index_iterator index_iterator;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename grid_type::math_types math_types;
typedef typename math_types::real_type real_type;
using std::min;
using std::max;
using std::fabs;
real_type dx = phi.dx();
real_type dy = phi.dy();
real_type dz = phi.dz();
grid_type F = phi;
real_type min_delta = min ( dx, min( dy, dz));
assert(min_delta>0 || !"metamorphosis(): minimum spacing was non-positive!");
real_type max_gamma = max ( fabs( max(gamma)), fabs( min(gamma) ) );
assert(max_gamma>0 || !"metamorphosis(): maximum absolute speed was non-positive!");
real_type time = static_cast<real_type>(0.0);
while (time < dt)
{
metamorphosis_speed_function(phi,gamma,F);
real_type time_step = min( dt, min_delta / (3.0*max_gamma) );
assert(time_step>0 || !"metamorphosis(): time_step was non-positive!");
std::cout << "\ttime step = " << time_step << std::endl;
index_iterator end = phi.end();
index_iterator u = phi.begin();
index_iterator f = F.begin();
for(;u!=end; ++u,++f)
(*u) = (*u) + time_step *(*f);
time += time_step;
}
std::cout << "metamorphosis(): done..." << std::endl;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_METAMORPHOSIS_H
#endif

View File

@@ -0,0 +1,48 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_OPENING_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_OPENING_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/grid_dilation.h>
#include <OpenTissue/core/containers/grid/util/grid_erosion.h>
namespace OpenTissue
{
namespace grid
{
/**
* Opening Operation.
*
* @param phi Input level set.
* @param radius Radius of spherical structural element.
* @param dt Time-step to use in update.
* @param psi Output levelset. Note if input is a signed distance map then output may not be a signed distance map, thus you may need to redistance output levelset.
*/
template<
typename grid_type_in
, typename real_type
, typename grid_type_out
>
inline void opening(
grid_type_in const & phi
, real_type const & radius
, real_type const & dt
, grid_type_out & psi
)
{
dilation(phi,radius,dt,psi);
erosion(psi,radius,dt,psi);
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_OPENING_H
#endif

View File

@@ -0,0 +1,177 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_POISSON_SOLVER_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_POISSON_SOLVER_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
#include <OpenTissue/core/containers/grid/util/grid_compute_sign_function.h>
#include <OpenTissue/core/math/math_vector3.h>
namespace OpenTissue
{
namespace grid
{
/**
* Gauss-Seidel Poisson Solver with Pure Von Neuman Boundary Conditions.
*
* Theory: Given the PDE
*
* \nabla^2 \phi = W
*
* Solve for phi. Writing out we have
*
* \frac{\partial^2}{\partial x^2} phi + \frac{\partial^2}{\partial y^2} phi + \frac{\partial^2}{\partial z^2} phi = W
*
* Using central diff approximation leads to
*
* a_2 ( phi_{i+1,j,k} + phi_{i-1,j,k} ) + a_1( phi_{i,j+1,k} + phi_{i,j-1,k} ) + a_0( phi_{i,j,k+1} + phi_{i,j,k-1} ) - a_3 W
* phi_{i,j,k} = --------------------------------------------------------------------------------------------------------------------------------
* 2 a_4
*
* where
*
* a_0 = (dx*dx*dy*dy)
* a_1 = (dx*dx*dz*dz)
* a_2 = (dy*dy*dz*dz)
* a_3 = (dx*dx*dy*dy*dz*dz)
* a_4 = a_0 + a_1 + a_2
*
* In case dx=dy=dz this simplifies to
*
* phi_{i+1,j,k} + phi_{i-1,j,k} + phi_{i,j+1,k} + phi_{i,j-1,k} + phi_{i,j,k+1} + phi_{i,j,k-1} - dx*dx W
* phi_{i,j,k} = ----------------------------------------------------------------------------------------------------------
* 8
*
* The solver uses pure Neumann bondary conditions. i.e.:
*
* \nabla phi = 0
*
* on any boundary. This means that values outside boundary are copied from
* nearest boundary voxel => claming out-of-bound indices onto boundary.
*
* @param phi Contains initial guess for solution, and upon
* return contains the solution.
* @param b The right hand side of the poisson equation.
* @param max_iterations The maximum number of iterations allowed. Default is 30 iterations.
*/
template < typename grid_type >
inline void poisson_solver(
grid_type & phi
, grid_type const & W
, size_t max_iterations = 10
)
{
using std::min;
typedef typename grid_type::value_type value_type;
typedef typename grid_type::const_iterator const_iterator;
typedef typename grid_type::index_iterator index_iterator;
typedef typename grid_type::math_types math_types;
typedef typename math_types::real_type real_type;
size_t I = phi.I();
size_t J = phi.J();
size_t K = phi.K();
real_type dx = phi.dx();
real_type dy = phi.dy();
real_type dz = phi.dz();
if(dx!=dy || dx!=dz || dy!=dz)
{
//std::cout << "poisson_solver(): non-uniform grid" << std::endl;
real_type a0 = dx*dx*dy*dy;
real_type a1 = dx*dx*dz*dz;
real_type a2 = dy*dy*dz*dz;
real_type a3 = dx*dx*dy*dy*dz*dz;
real_type a4 = 1.0/(2*(a0 + a1 + a2));
for(size_t iteration=0;iteration<max_iterations;++iteration)
{
index_iterator p = phi.begin();
index_iterator p_end = phi.end();
const_iterator w = W.begin();
for(;p!=p_end;++p,++w)
{
size_t i = p.i();
size_t j = p.j();
size_t k = p.k();
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
//size_t idx = ( k * J + j ) * I + i;
size_t idx_im1 = ( k * J + j ) * I + im1;
size_t idx_ip1 = ( k * J + j ) * I + ip1;
size_t idx_jm1 = ( k * J + jm1 ) * I + i;
size_t idx_jp1 = ( k * J + jp1 ) * I + i;
size_t idx_km1 = ( km1 * J + j ) * I + i;
size_t idx_kp1 = ( kp1 * J + j ) * I + i;
//real_type v000 = phi(idx);
real_type vm00 = phi(idx_im1);
real_type vp00 = phi(idx_ip1);
real_type v0m0 = phi(idx_jm1);
real_type v0p0 = phi(idx_jp1);
real_type v00m = phi(idx_km1);
real_type v00p = phi(idx_kp1);
*p = ( a2*( vp00 + vm00 ) + a1*(v0p0+v0m0) + a0*(v00p + v00m) - a3*(*w)) * a4;
}
}
}
else
{
//std::cout << "poisson_solver(): uniform grid, dx=dy=dz" << std::endl;
real_type a0 = dx*dx;
real_type a1 = 1.0/8.0;
for(size_t iteration=0;iteration<max_iterations;++iteration)
{
index_iterator p = phi.begin();
index_iterator p_end = phi.end();
const_iterator w = W.begin();
for(;p!=p_end;++p,++w)
{
size_t i = p.i();
size_t j = p.j();
size_t k = p.k();
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
//size_t idx = ( k * J + j ) * I + i;
size_t idx_im1 = ( k * J + j ) * I + im1;
size_t idx_ip1 = ( k * J + j ) * I + ip1;
size_t idx_jm1 = ( k * J + jm1 ) * I + i;
size_t idx_jp1 = ( k * J + jp1 ) * I + i;
size_t idx_km1 = ( km1 * J + j ) * I + i;
size_t idx_kp1 = ( kp1 * J + j ) * I + i;
//real_type v000 = phi(idx);
real_type vm00 = phi(idx_im1);
real_type vp00 = phi(idx_ip1);
real_type v0m0 = phi(idx_jm1);
real_type v0p0 = phi(idx_jp1);
real_type v00m = phi(idx_km1);
real_type v00p = phi(idx_kp1);
*p = ( vp00 + vm00 + v0p0+v0m0 + v00p + v00m - a0*(*w) ) *a1;
}
}
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_POISSON_SOLVER_H
#endif

View File

@@ -0,0 +1,368 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_REDISTANCE_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_REDISTANCE_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
#include <OpenTissue/core/math/math_is_finite.h>
#include <OpenTissue/core/math/math_vector3.h>
#include <OpenTissue/core/containers/grid/util/grid_compute_sign_function.h>
namespace OpenTissue
{
namespace grid
{
namespace detail
{
class FullRedistance
{
protected:
template < typename grid_type >
typename grid_type::value_type compute_speed(
grid_type const & phi
, grid_type const & S0
, grid_type & speed
)
{
using std::min;
using std::max;
using std::sqrt;
using std::fabs;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename grid_type::const_iterator const_iterator;
typedef typename grid_type::iterator iterator;
typedef typename grid_type::math_types math_types;
typedef typename math_types::value_type real_type;
assert(phi.I()==S0.I() || !"compute_speed(): incompatible grid dimensions");
assert(phi.J()==S0.J() || !"compute_speed(): incompatible grid dimensions");
assert(phi.K()==S0.K() || !"compute_speed(): incompatible grid dimensions");
assert(phi.min_coord()==S0.min_coord() || !"compute_speed(): incompatible grid side lengths");
assert(phi.max_coord()==S0.max_coord() || !"compute_speed(): incompatible grid side lengths");
speed.create(phi.min_coord(),phi.max_coord(),phi.I(),phi.J(),phi.K());
real_type inv_dx = static_cast<real_type> ( 1.0 / phi.dx());
real_type inv_dy = static_cast<real_type> ( 1.0 / phi.dy());
real_type inv_dz = static_cast<real_type> ( 1.0 / phi.dz());
real_type inv_dx2 = inv_dx*inv_dx;
real_type inv_dy2 = inv_dx*inv_dy;
real_type inv_dz2 = inv_dx*inv_dz;
real_type cfl_condition = real_type(0.0);
real_type zero = static_cast<real_type>(0.0);
iterator f = speed.begin();
const_index_iterator p = phi.begin();
const_index_iterator end = phi.end();
const_iterator s0 = S0.begin();
size_t I = phi.I();
size_t J = phi.J();
size_t K = phi.K();
for ( ; p != end; ++p, ++f,++s0)
{
size_t i = p.i();
size_t j = p.j();
size_t k = p.k();
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1, I - 1 );
size_t jp1 = min( j + 1, J - 1 );
size_t kp1 = min( k + 1, K - 1 );
size_t idx_000 = ( k * J + j ) * I + i;
size_t idx_m00 = ( k * J + j ) * I + im1;
size_t idx_p00 = ( k * J + j ) * I + ip1;
size_t idx_0m0 = ( k * J + jm1 ) * I + i;
size_t idx_0p0 = ( k * J + jp1 ) * I + i;
size_t idx_00m = ( km1 * J + j ) * I + i;
size_t idx_00p = ( kp1 * J + j ) * I + i;
real_type d000 = phi( idx_000 );
real_type dp00 = phi( idx_p00 );
real_type dm00 = phi( idx_m00 );
real_type d0p0 = phi( idx_0p0 );
real_type d0m0 = phi( idx_0m0 );
real_type d00p = phi( idx_00p );
real_type d00m = phi( idx_00m );
assert( is_finite( d000 ) || !"compute_speed(): NaN encountered");
assert( is_finite( dp00 ) || !"compute_speed(): NaN encountered");
assert( is_finite( dm00 ) || !"compute_speed(): NaN encountered");
assert( is_finite( d0p0 ) || !"compute_speed(): NaN encountered");
assert( is_finite( d0m0 ) || !"compute_speed(): NaN encountered");
assert( is_finite( d00p ) || !"compute_speed(): NaN encountered");
assert( is_finite( d00m ) || !"compute_speed(): NaN encountered");
real_type dxp = (dp00 - d000)*inv_dx;
real_type dxm = (d000 - dm00)*inv_dx;
real_type dyp = (d0p0 - d000)*inv_dy;
real_type dym = (d000 - d0m0)*inv_dy;
real_type dzp = (d00p - d000)*inv_dz;
real_type dzm = (d000 - d00m)*inv_dz;
assert( is_finite( dxp ) || !"compute_speed(): NaN encountered");
assert( is_finite( dxm ) || !"compute_speed(): NaN encountered");
assert( is_finite( dyp ) || !"compute_speed(): NaN encountered");
assert( is_finite( dym ) || !"compute_speed(): NaN encountered");
assert( is_finite( dzp ) || !"compute_speed(): NaN encountered");
assert( is_finite( dzm ) || !"compute_speed(): NaN encountered");
real_type dxp_max = max( dxp, zero );
real_type dxm_max = max( dxm, zero );
real_type dyp_max = max( dyp, zero );
real_type dym_max = max( dym, zero );
real_type dzp_max = max( dzp, zero );
real_type dzm_max = max( dzm, zero );
real_type dxp_min = min( dxp, zero );
real_type dxm_min = min( dxm, zero );
real_type dyp_min = min( dyp, zero );
real_type dym_min = min( dym, zero );
real_type dzp_min = min( dzp, zero );
real_type dzm_min = min( dzm, zero );
real_type dxp_max_2 = dxp_max * dxp_max;
real_type dxm_max_2 = dxm_max * dxm_max;
real_type dyp_max_2 = dyp_max * dyp_max;
real_type dym_max_2 = dym_max * dym_max;
real_type dzp_max_2 = dzp_max * dzp_max;
real_type dzm_max_2 = dzm_max * dzm_max;
real_type dxp_min_2 = dxp_min * dxp_min;
real_type dxm_min_2 = dxm_min * dxm_min;
real_type dyp_min_2 = dyp_min * dyp_min;
real_type dym_min_2 = dym_min * dym_min;
real_type dzp_min_2 = dzp_min * dzp_min;
real_type dzm_min_2 = dzm_min * dzm_min;
// yellowbook p58
real_type phi_x_2_p = max( dxm_max_2, dxp_min_2 );
real_type phi_x_2_m = max( dxm_min_2, dxp_max_2 );
real_type phi_y_2_p = max( dym_max_2, dyp_min_2 );
real_type phi_y_2_m = max( dym_min_2, dyp_max_2 );
real_type phi_z_2_p = max( dzm_max_2, dzp_min_2 );
real_type phi_z_2_m = max( dzm_min_2, dzp_max_2 );
// peng99 eq40
real_type norm_grad_phi_p = sqrt( phi_x_2_p + phi_y_2_p + phi_z_2_p );
real_type norm_grad_phi_m = sqrt( phi_x_2_m + phi_y_2_m + phi_z_2_m );
// Godunov scheme (yellowbook p58 eq6.3 and 6.4)
if ( (*s0) > 0 )
{
(*f) = (*s0) * ( norm_grad_phi_p - 1.0 );
}
else if ( (*s0) < 0 )
{
(*f) = (*s0) * ( norm_grad_phi_m - 1.0 );
}
else
{
(*f) = 0;
}
real_type phi_x = fabs((dp00 - dm00)*inv_dx*.5);
real_type phi_y = fabs((d0p0 - d0m0)*inv_dy*.5);
real_type phi_z = fabs((d00p - d00m)*inv_dz*.5);
real_type norm_grad_phi = sqrt(phi_x*phi_x + phi_y*phi_y + phi_z*phi_z);
real_type tmp = fabs( (*s0)*phi_x*inv_dx2/norm_grad_phi + (*s0)*phi_y*inv_dy2/norm_grad_phi + (*s0)*phi_z*inv_dz2/norm_grad_phi );
cfl_condition = max( cfl_condition, tmp );
}
return 1.0/cfl_condition;
}
template < typename grid_type , typename real_type >
real_type update(
grid_type const & phi
, grid_type const & speed
, real_type const & time_step
, grid_type & psi
, real_type const & gamma = 10e30
)
{
typedef typename grid_type::const_index_iterator const_iterator;
typedef typename grid_type::iterator iterator;
assert(phi.I()==psi.I() || !"update(): incompatible grid dimensions");
assert(phi.J()==psi.J() || !"update(): incompatible grid dimensions");
assert(phi.K()==psi.K() || !"update(): incompatible grid dimensions");
assert(phi.min_coord()==psi.min_coord() || !"update(): incompatible grid side lengths");
assert(phi.max_coord()==psi.max_coord() || !"update(): incompatible grid side lengths");
assert(time_step>0 || !"update(): time-step must be positive");
real_type steady = real_type(0.0);
const_iterator i = phi.begin();
const_iterator f = speed.begin();
iterator o = psi.begin();
const_iterator end = phi.end();
for ( ; i!=end;++i, ++o, ++f)
{
real_type diff = time_step * (*f);
(*o) = (*i) - diff;
diff = std::fabs(diff);
if ( (*o) < gamma && steady < diff )
steady = diff;
}
return steady;
}
public:
/**
* Signed Distance Map Reinitialization.
*
* Brute-force implementation of the reinitialization of the distance function.
* The following Hamilton-Jacobi equation is solved:
* d_tau + S(d) * ( |grad phi| - 1 ) = 0
* d(x,0) = d_0(x) = phi(x,t)
* to steady state, with S(d) approximated by:
* s = d / ( sqrt( d^2 + |Dd|^2 * delta_x^2) )
*
* Calculates gradient magnitude of phi using upwind-scheme.
* Performs PDE update using forward Euler time discretization.
*
* @param phi Input level set that should be redistanced into a signed distance grid.
* @param psi Output level set. That is the redistaned phi.
* @param max_iterations The maximum number of iterations allowed to do re-initialization.
* @param stead_threshold The threshold value used to test for steady state.
*/
template < typename grid_type >
void operator()(
grid_type const & phi
, grid_type & psi
, size_t max_iterations = 10
, double steady_threshold = 0.05
)
{
using std::min;
using std::max;
typedef typename grid_type::value_type real_type;
assert(phi.I()==psi.I() || !"operator(): incompatible grid dimensions");
assert(phi.J()==psi.J() || !"operator(): incompatible grid dimensions");
assert(phi.K()==psi.K() || !"operator(): incompatible grid dimensions");
assert(phi.min_coord()==psi.min_coord() || !"operator(): incompatible grid side lengths");
assert(phi.max_coord()==psi.max_coord() || !"operator(): incompatible grid side lengths");
static grid_type S0; // TODO: Hmm, these temporaries take up a lot of space!!!
static grid_type speed;
compute_sign_function(phi,S0);
real_type alpha = static_cast<real_type> ( 0.9 ); //--- CFL number
//real_type min_delta = static_cast<real_type> ( (min( phi.dx(), min( phi.dy(), phi.dz() ) ) ) );
real_type max_delta = static_cast<real_type> ( (max( phi.dx(), max( phi.dy(), phi.dz() ) ) ) );
grid_type * phi_in = const_cast<grid_type*>(&phi);
grid_type * phi_out = &psi;
real_type gamma = static_cast<real_type>( max_delta * max_iterations );
real_type steady = static_cast<real_type>(0.0);
for(size_t iterations=0;iterations<max_iterations;++iterations)
{
for ( size_t flipflop = 2; flipflop; --flipflop )
{
std::swap( phi_in, phi_out );
real_type cfl_condition = compute_speed( (*phi_in) ,S0,speed);
//--- CFL condition (yellowbook p50)
//---
//--- Given PDE:
//---
//--- phi_t + H(\nabla \phi) = 0
//---
//--- CFL condition is
//---
//--- \delta t \max \left{
//--- \frac{|H_{\phi_x}|}{delta_x^2}
//--- +
//--- \frac{|H_{\phi_y}|}{delta_y^2}
//--- +
//--- \frac{|H_{\phi_z}|}{delta_z^2}
//--- \right} < alpha
//---
//--- where 0 < alpha < 1 is the CFL number (see pp 30 eq. 3.9). From this we pick the time step \delta t as
//---
//--- delta_t = alpha /
//--- \left{
//--- \frac{|H_{\phi_x}|}{delta_x^2}
//--- +
//--- \frac{|H_{\phi_y}|}{delta_y^2}
//--- +
//--- \frac{|H_{\phi_z}|}{delta_z^2}
//--- \right}
//---
//--- In our case
//---
//--- H = s(|\nabla \phi| -1 )
//---
//--- So
//---
//--- H_{\phi_x} = \frac{ s \phi_x }{ |\nabla \phi| }
//---
//--- And we find
//---
//--- delta_t = alpha /
//--- \left{
//--- \frac{|s \phi_x}|}{|\nabla \phi| delta_x^2}
//--- +
//--- \frac{|s \phi_y}|}{|\nabla \phi| delta_y^2}
//--- +
//--- \frac{|s \phi_z}|}{|\nabla \phi| delta_z^2}
//--- \right}
//---
//---
real_type time_step = alpha*cfl_condition;
std::cout << "\ttime step = " << time_step << std::endl;
steady = update( (*phi_in), speed, time_step, (*phi_out), gamma);
}
std::cout << "\tredistance(): iteration = " << iterations << " steady = " << steady <<std::endl;
if(steady < steady_threshold)
break;
}
}
};
}// namespace detail
/**
* Signed Distance Map Reinitialization.
*
* Brute-force implementation of the reinitialization of the distance function.
* The following Hamilton-Jacobi equation is solved:
* d_tau + S(d) * ( |grad phi| - 1 ) = 0
* d(x,0) = d_0(x) = phi(x,t)
* to steady state, with S(d) approximated by:
* s = d / ( sqrt( d^2 + |Dd|^2 * delta_x^2) )
*
* Calculates gradient magnitude of phi using upwind-scheme.
* Performs PDE update using forward Euler time discretization.
*
* @param phi Input level set that should be redistanced into a signed distance grid.
* @param psi Output level set. That is the redistanced phi.
* @param max_iterations The maximum number of iterations allowed to do re-initialization.
* @param stead_threshold The threshold value used to test for steady state.
*/
template < typename grid_type >
inline void redistance(
grid_type const & phi
, grid_type & psi
, size_t max_iterations = 10
, double steady_threshold = 0.05
)
{
static detail::FullRedistance redistance_class;
redistance_class(phi,psi,max_iterations,steady_threshold);
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_REDISTANCE_H
#endif

View File

@@ -0,0 +1,66 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_RESAMPLE_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_RESAMPLE_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
#include <OpenTissue/core/containers/grid/util/grid_value_at_point.h>
#include <OpenTissue/core/containers/grid/util/grid_idx2coord.h>
namespace OpenTissue
{
namespace grid
{
/**
* Resample a grid to lower dimensions.
* @param M Original grid to be resampled.
* @param m Destination grid.
* @param factor_i Scale factor in the I-direction of the grid.
* @param factor_j Scale factor in the J-direction of the grid.
* @param factor_k Scale factor in the K-direction of the grid.
* @return Upon return the destination grid m contains the resampled grid.
*/
template <typename grid_type, typename real_type>
inline void resample(grid_type const & M, grid_type & m, real_type factor_i, real_type factor_j, real_type factor_k)
{
using std::floor;
assert(factor_i > 0 || !"resample(): i scale factor must be positive");
assert(factor_j > 0 || !"resample(): j scale factor must be positive");
assert(factor_k > 0 || !"resample(): k scale factor must be positive");
typedef typename grid_type::math_types math_types;
typedef typename math_types::vector3_type vector3_type;
typedef typename grid_type::index_iterator index_iterator;
// TODO: Add gaussian smoothing with a standard deviation corresponding to factor_n.
//grid_type S = M;
//grid_gaussian_convolution(M,S,factor_i/2.0,factor_j/2.0,factor_k/2.0);
m.create(
M.min_coord(), M.max_coord()
, static_cast<size_t>( floor(M.I()/factor_i) )
, static_cast<size_t>( floor(M.J()/factor_j) )
, static_cast<size_t>( floor(M.K()/factor_k) )
);
vector3_type point;
for( index_iterator iter = m.begin(); iter != m.end(); ++iter )
{
idx2coord( iter,point );
(*iter) = value_at_point( M, point );
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_RESAMPLE_H
#endif

View File

@@ -0,0 +1,86 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_SECOND_DERIVATVE_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_SECOND_DERIVATVE_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/grid_gradient.h>
#include <OpenTissue/core/containers/grid/util/grid_hessian.h>
#include <OpenTissue/core/math/math_vector3.h> // Needed for vector3.
#include <OpenTissue/core/math/math_matrix3x3.h> // Needed for matrix3x3.
namespace OpenTissue
{
namespace grid
{
template<typename grid_type, typename real_type>
inline void second_derivative(
grid_type const & grid
, size_t i
, size_t j
, size_t k
, real_type & derivative
)
{
using std::fabs;
typedef OpenTissue::math::Vector3<real_type> vector3_type;
typedef OpenTissue::math::Matrix3x3<real_type> matrix3x3_type;
static vector3_type g;
static matrix3x3_type H;
real_type const too_small = 10e-7;
gradient(grid, i, j, k, g );
real_type tmp = g*g;
if(fabs(tmp) < too_small)
{
derivative = 0.0;
return;
}
hessian(grid, i, j, k, H);
derivative = (1.0)/(tmp)* (g * (H *g));
}
template<typename grid_iterator,typename real_type>
inline void second_derivative (grid_iterator const & iter, real_type & derivative)
{
typedef typename grid_iterator::grid_type grid_type;
size_t i = iter.i();
size_t j = iter.j();
size_t k = iter.k();
grid_type const & grid = iter.get_grid();
second_derivative(grid, i, j, k, derivative);
}
template<typename grid_iterator>
inline typename grid_iterator::math_types::real_type
second_derivative( grid_iterator const & iter )
{
typedef typename grid_iterator::math_types::real_type real_type;
real_type derivative;
second_derivative(iter, derivative);
return derivative;
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_SECOND_DERIVATVE_H
#endif

View File

@@ -0,0 +1,63 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_SPLIT2SLICES_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_SPLIT2SLICES_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cassert>
namespace OpenTissue
{
namespace grid
{
/**
* Split a 3D grid into multiple 2D grids along some major axis.
*
* @param grid The grid that should be split inot slices.
* @param slices Upon return this container holds grids corresponding to all the slices.
* @param axis The axis to split along.
*/
template <typename grid_type,typename grid_container>
inline void split2slices(grid_type & grid, grid_container & slices, size_t axis = 2)
{
typename grid_type::math_types math_types;
typename math_types::vector3_type vector3_type;
assert( axis==2 || !"split2slices(): Only splits along k-axis is currently supported");
slices.clear();
if (axis != 2)
return;
vector3_type min_coord = grid.min_coord();
vector3_type max_coord = grid.max_coord();
min_coord(2) = 0;
max_coord(2) = 0;
for (size_t z = 0; z < grid.K(); ++z)
{
grid_type slice;
slice.create(min_coord, max_coord, grid.I(), grid.J(), 2);
for (size_t y = 0; y < grid.J(); ++y)
for (size_t x = 0; x < grid.I(); ++x)
{
slice(x, y, 0) = grid(x, y, z);
slice(x, y, 1) = grid(x, y, z); // HACKING!!!
}
slices.push_back(slice);
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_SPLIT2SLICES_H
#endif

View File

@@ -0,0 +1,160 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_STRICT_GRID_LOCAL_MINIMA_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_STRICT_GRID_LOCAL_MINIMA_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/grid_idx2coord.h>
#include <cmath>
namespace OpenTissue
{
namespace grid
{
namespace detail
{
/**
* Test if a specified node is a strict local minima.
*
* @param i
* @param j
* @param k
* @param phi
*
* @return True if node i,j,k is a local minima, otherwise false.
*/
template < typename grid_type >
inline bool is_strict_local_minima(
size_t i
, size_t j
, size_t k
, grid_type const & phi
)
{
using std::min;
static size_t idx[27];
size_t I = phi.I();
size_t J = phi.J();
size_t K = phi.K();
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
idx[0] = ( kp1 * J + jp1 ) * I + im1;
idx[1] = ( k * J + jp1 ) * I + im1;
idx[2] = ( km1 * J + jp1 ) * I + im1;
idx[3] = ( kp1 * J + j ) * I + im1;
idx[4] = ( k * J + j ) * I + im1;
idx[5] = ( km1 * J + j ) * I + im1;
idx[6] = ( kp1 * J + jm1 ) * I + im1;
idx[7] = ( k * J + jm1 ) * I + im1;
idx[8] = ( km1 * J + jm1 ) * I + im1;
idx[9] = ( kp1 * J + jp1 ) * I + i;
idx[10] = ( k * J + jp1 ) * I + i;
idx[11] = ( km1 * J + jp1 ) * I + i;
idx[12] = ( kp1 * J + j ) * I + i;
idx[13] = ( k * J + j ) * I + i;
idx[14] = ( km1 * J + j ) * I + i;
idx[15] = ( kp1 * J + jm1 ) * I + i;
idx[16] = ( k * J + jm1 ) * I + i;
idx[17] = ( km1 * J + jm1 ) * I + i;
idx[18] = ( kp1 * J + jp1 ) * I + ip1;
idx[19] = ( k * J + jp1 ) * I + ip1;
idx[20] = ( km1 * J + jp1 ) * I + ip1;
idx[21] = ( kp1 * J + j ) * I + ip1;
idx[22] = ( k * J + j ) * I + ip1;
idx[23] = ( km1 * J + j ) * I + ip1;
idx[24] = ( kp1 * J + jm1 ) * I + ip1;
idx[25] = ( k * J + jm1 ) * I + ip1;
idx[26] = ( km1 * J + jm1 ) * I + ip1;
for(size_t i=0;i<27u;++i)
if( phi(idx[13]) >= phi(idx[i]) )
return false;
return true;
}
} // namespace detail
/**
* Extract local minima nodes.
* Note that local minima may exist at non-nodal locations. This function
* only considers nodal positions. Thus if you are looking for local minima
* at sub-pixel accuracy, then you need another approach.
*
* @param phi The map from where local minima nodes should be extracted from.
* @param points Upon return this container contains all the coordinates of all nodes that where local minima.
*/
template < typename grid_type,typename point_container >
inline void strict_local_minima_as_points(
grid_type const & phi
, point_container & points
)
{
typedef typename point_container::value_type vector3_type;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename vector3_type::value_type real_type;
typedef typename grid_type::value_type value_type;
const_index_iterator pend = phi.end();
const_index_iterator p = phi.begin();
for(;p!=pend;++p)
{
if(detail::is_strict_local_minima(p.i(),p.j(),p.k(),phi))
{
vector3_type point;
idx2coord(phi,p.i(),p.j(),p.k(),point);
points.push_back(point);
}
}
}
/**
* Extract Strict Local Minima as Points.
*
* @param phi
* @param mask A mask that can be used to mask-out nodes in phi, which is not
* of interest. Positive values correspond to nodes that are allowed
* to be classified as local minima.
* @param points
*/
template < typename grid_type,typename point_container >
inline void strict_local_minima_as_points(
grid_type const & phi
, grid_type const & mask
, point_container & points
)
{
typedef typename point_container::value_type vector3_type;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename vector3_type::value_type real_type;
typedef typename grid_type::value_type value_type;
const_index_iterator end = phi.end();
const_index_iterator p = phi.begin();
const_index_iterator m = mask.begin();
for(;p!=end;++p,++m)
{
if( (*m) <= 0 )
continue;
if(detail::is_strict_local_minima(p.i(),p.j(),p.k(),phi))
{
vector3_type point;
idx2coord(phi,p.i(),p.j(),p.k(),point);
points.push_back(point);
}
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_STRICT_GRID_LOCAL_MINIMA_H
#endif

View File

@@ -0,0 +1,87 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_TRANSLATE_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_TRANSLATE_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <boost/iterator/reverse_iterator.hpp>
#include <cstdlib> // for abs()
namespace OpenTissue
{
namespace grid
{
/**
* Translate a grid by an integer vector and wrap around at border.
*
* Behavior is un-expected if input and output grid is the same....
* TODO: make it work for zero-trans and negative trans.
*
* @param src Source grid to be translated.
* @param v translation vector.
* @param dst Upon return, contains the translated grid.
*/
template <typename grid_type, typename vector3_int_type>
inline void translate(grid_type const& src, vector3_int_type const& v, grid_type & dst)
{
assert( v(0)>0 && !"translate(): Only works for positive translations for now");
assert( v(1)>0 && !"translate(): Only works for positive translations for now");
assert( v(2)>0 && !"translate(): Only works for positive translations for now");
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename grid_type::math_types math_types;
typedef typename math_types::vector3_type vector3_type;
// make sure translation is >0
vector3_int_type t=v;
//if( t(0)<0 )
// t(0) += src.I()*(1+abs(t(0)/src.I()));
//if( t(1)<0 )
// t(1) += src.J()*(1+abs(t(1)/src.J()));
//if( t(2)<0 )
// t(2) += src.K()*(1+abs(t(2)/src.K()));
// Save last block of data
grid_type tmp;
tmp.create(vector3_type(0,0,0), vector3_type(1,1,1), t(0), t(1), t(2));
size_t ti = src.I()-t(0);
size_t tj = src.J()-t(1);
size_t tk = src.K()-t(2);
size_t lk=0;
size_t lj=0;
size_t li=0;
for (size_t gk=tk; gk<src.K(); ++gk, ++lk)
for (size_t gj=tj; gj<src.J(); ++gj, ++lj)
for (size_t gi=ti; gi<src.I(); ++gi, ++li)
tmp(li,lj,lk) = src(gi,gj,gk);
// do translation (copy backwards)
// TODO: implement proper reverse_iterator_stuff
//boost::reverse_iterator<grid_type::const_index_iterator> p( src.end() ), end( src.begin() );
//for(p; p!=end; ++p)
//{
// dst( (p.base().i()+t(0))%src.I(), (p.base().j()+t(1))%src.J(), (p.base().k()+t(2))%src.K() ) = *p;
//}
for(const_index_iterator p=src.end()-1; p!=src.begin()-1; --p)
{
dst( (p.i()+t(0))%src.I(), (p.j()+t(1))%src.J(), (p.k()+t(2))%src.K() ) = *p;
}
// copy over the stored values
for (size_t k=0; k<tmp.K(); ++k)
for (size_t j=0; j<tmp.J(); ++j)
for (size_t i=0; i<tmp.I(); ++i)
dst(i,j,k) = tmp(i,j,k);
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_TRANSLATE_H
#endif

View File

@@ -0,0 +1,62 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_UNIFORM_POINT_SAMPLING_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_UNIFORM_POINT_SAMPLING_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/grid/util/functions.h> //--- needed for gradient_func and value_func
namespace OpenTissue
{
namespace grid
{
/**
* Uniform Point Sampling of Grid.
*
* @param phi The (signed distance grid) level set grid.
* @param points Upon return this container containts the random points.
* @param sub_Sample Optimal argument, allows one to control the density of points.
*/
template<typename grid_type,typename vector3_container>
inline void uniform_point_sampling(
grid_type const & phi
, vector3_container & points
, size_t sub_sample = 2u
)
{
typedef typename vector3_container::value_type vector3_type;
typedef typename vector3_type::value_type real_type;
points.clear();
real_type min_x = phi.min_coord(0);
real_type min_y = phi.min_coord(1);
real_type min_z = phi.min_coord(2);
real_type max_x = phi.max_coord(0);
real_type max_y = phi.max_coord(1);
real_type max_z = phi.max_coord(2);
real_type dx = phi.dx()*sub_sample;
real_type dy = phi.dy()*sub_sample;
real_type dz = phi.dz()*sub_sample;
for ( real_type x = (min_x+dx); x < (max_x-dx); x += dx )
for ( real_type y = (min_y+dy); y < (max_y-dy); y += dy )
for ( real_type z = (min_z+dz); z < (max_z-dz); z += dz )
{
points.push_back( vector3_type( x, y, z ) );
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_UNIFORM_POINT_SAMPLING_H
#endif

View File

@@ -0,0 +1,107 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_UPWIND_GRADIENT_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_UPWIND_GRADIENT_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
namespace OpenTissue
{
namespace grid
{
/**
* Compute Upwind Gradient at Specified Node location.
*
* @param phi A the map in which we want to know the gradient.
* @param F A map containing the values of the speed function.
* @param i The i'th index of the node at which we want to compute the gradient.
* @param j The j'th index of the node at which we want to compute the gradient.
* @param k The k'th index of the node at which we want to compute the gradient.
* @param gradient Upon completion contains the upwind gradient
*/
template<typename grid_type, typename vector3_type>
inline void upwind_gradient(
grid_type const & phi
, grid_type const & F
, size_t i
, size_t j
, size_t k
, vector3_type & gradient
)
{
using std::min;
typedef typename grid_type::value_type value_type;
typedef typename grid_type::math_types math_types;
typedef typename math_types::real_type real_type;
size_t I = phi.I();
size_t J = phi.J();
size_t K = phi.K();
real_type inv_dx = 1.0/phi.dx();
real_type inv_dy = 1.0/phi.dy();
real_type inv_dz = 1.0/phi.dz();
real_type inv_2dx = 0.5/phi.dx();
real_type inv_2dy = 0.5/phi.dy();
real_type inv_2dz = 0.5/phi.dz();
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
size_t i000 = ( k * J + j ) * I + i;
size_t im00 = ( k * J + j ) * I + im1;
size_t ip00 = ( k * J + j ) * I + ip1;
size_t i0m0 = ( k * J + jm1 ) * I + i;
size_t i0p0 = ( k * J + jp1 ) * I + i;
size_t i00m = ( km1 * J + j ) * I + i;
size_t i00p = ( kp1 * J + j ) * I + i;
real_type f = F(i000);
real_type v000 = phi(i000);
real_type vp00 = phi(ip00);
real_type vm00 = phi(im00);
real_type v0p0 = phi(i0p0);
real_type v0m0 = phi(i0m0);
real_type v00p = phi(i00p);
real_type v00m = phi(i00m);
// phi^t+1 = phi_t + dt*F
// F > 0 use forward diffs
// F < 0 use backward diffs
real_type nx = 0;
real_type ny = 0;
real_type nz = 0;
if(f>0)
{
nx = (vp00 - v000 ) * inv_dx;
ny = (v0p0 - v000 ) * inv_dy;
nz = (v00p - v000 ) * inv_dz;
}
else if(f<0)
{
nx = (v000 - vm00) * inv_dx;
ny = (v000 - v0m0) * inv_dy;
nz = (v000 - v00m) * inv_dz;
}
else
{
nx = (vp00 - vm00) * inv_2dx;
ny = (v0p0 - v0m0) * inv_2dy;
nz = (v00p - v00m) * inv_2dz;
}
gradient = vector3_type(nx,ny,nz);
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_UPWIND_GRADIENT_H
#endif

View File

@@ -0,0 +1,115 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_UPWIND_GRADIENT_FIELD_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_UPWIND_GRADIENT_FIELD_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cmath>
namespace OpenTissue
{
namespace grid
{
/**
* Picks upwind direction of gradient according to the speed function (F).
*/
template < typename grid_type >
inline void upwind_gradient_field(
grid_type const & phi
, grid_type const & F
, grid_type & Nx
, grid_type & Ny
, grid_type & Nz
)
{
using std::min;
typedef OpenTissue::math::Vector3< typename grid_type::value_type> vector3_type;
typedef typename grid_type::value_type value_type;
typedef typename grid_type::iterator iterator;
typedef typename grid_type::const_iterator const_iterator;
typedef typename grid_type::const_index_iterator const_index_iterator;
typedef typename grid_type::math_types math_types;
typedef typename math_types::real_type real_type;
size_t I = phi.I();
size_t J = phi.J();
size_t K = phi.K();
real_type inv_dx = 1.0/phi.dx();
real_type inv_dy = 1.0/phi.dy();
real_type inv_dz = 1.0/phi.dz();
real_type inv_2dx = 0.5/phi.dx();
real_type inv_2dy = 0.5/phi.dy();
real_type inv_2dz = 0.5/phi.dz();
iterator nx = Nx.begin();
iterator ny = Ny.begin();
iterator nz = Nz.begin();
const_iterator f = F.begin();
const_index_iterator pbegin = phi.begin();
const_index_iterator pend = phi.end();
const_index_iterator p = pbegin;
for(;p!=pend; ++f,++p,++nx,++ny,++nz)
{
size_t i = p.i();
size_t j = p.j();
size_t k = p.k();
size_t im1 = ( i ) ? i - 1 : 0;
size_t jm1 = ( j ) ? j - 1 : 0;
size_t km1 = ( k ) ? k - 1 : 0;
size_t ip1 = min( i + 1u, I - 1u );
size_t jp1 = min( j + 1u, J - 1u );
size_t kp1 = min( k + 1u, K - 1u );
size_t i000 = ( k * J + j ) * I + i;
size_t im00 = ( k * J + j ) * I + im1;
size_t ip00 = ( k * J + j ) * I + ip1;
size_t i0m0 = ( k * J + jm1 ) * I + i;
size_t i0p0 = ( k * J + jp1 ) * I + i;
size_t i00m = ( km1 * J + j ) * I + i;
size_t i00p = ( kp1 * J + j ) * I + i;
real_type v000 = phi(i000);
real_type vp00 = phi(ip00);
real_type vm00 = phi(im00);
real_type v0p0 = phi(i0p0);
real_type v0m0 = phi(i0m0);
real_type v00p = phi(i00p);
real_type v00m = phi(i00m);
// phi^t+1 = phi_t + dt*F
// F > 0 use forward diffs
// F < 0 use backward diffs
if((*f)>0)
{
*nx = (vp00 - v000 ) * inv_dx;
*ny = (v0p0 - v000 ) * inv_dy;
*nz = (v00p - v000 ) * inv_dz;
}
else if((*f)<0)
{
*nx = (v000 - vm00) * inv_dx;
*ny = (v000 - v0m0) * inv_dy;
*nz = (v000 - v00m) * inv_dz;
}
else
{
*nx = (vp00 - vm00) * inv_2dx;
*ny = (v0p0 - v0m0) * inv_2dy;
*nz = (v00p - v00m) * inv_2dz;
}
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_UPWIND_GRADIENT_FIELD_H
#endif

View File

@@ -0,0 +1,77 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_VALUE_AT_POINT_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_VALUE_AT_POINT_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/math/math_trillinear.h>
#include <OpenTissue/core/containers/grid/util/grid_enclosing_indices.h>
namespace OpenTissue
{
namespace grid
{
/**
*
*
* Warning this method do not test whether the point lies inside the grid. If the point is
* outside the behavior is undefined.
*/
template<typename grid_type,typename vector3_type>
inline typename grid_type::value_type value_at_point(grid_type const & grid, vector3_type const & point )
{
typedef typename grid_type::value_type value_type;
typedef typename vector3_type::value_type real_type;
//const static value_type infty = grid.infinity();
const static value_type unused = grid.unused();
const static value_type zero = value_type(); //--- by standard default constructed is zero!!!
size_t i0, j0, k0, i1, j1, k1;
enclosing_indices( grid, point, i0, j0, k0, i1, j1, k1 );
value_type d000 = grid( i0, j0, k0 );
value_type d001 = grid( i1, j0, k0 );
value_type d010 = grid( i0, j1, k0 );
value_type d011 = grid( i1, j1, k0 );
value_type d100 = grid( i0, j0, k1 );
value_type d101 = grid( i1, j0, k1 );
value_type d110 = grid( i0, j1, k1 );
value_type d111 = grid( i1, j1, k1 );
size_t cnt_unused = 0;
#define MAGIC(val) \
if ( (val) == unused) { \
(val) = zero; \
++cnt_unused; \
}
MAGIC( d000 );
MAGIC( d001 );
MAGIC( d010 );
MAGIC( d011 );
MAGIC( d100 );
MAGIC( d101 );
MAGIC( d110 );
MAGIC( d111 );
#undef MAGIC
if ( cnt_unused == 8 )
return unused;
real_type s = ( point(0) - ( i0*grid.dx() + grid.min_coord(0) ) ) / grid.dx();
real_type t = ( point(1) - ( j0*grid.dy() + grid.min_coord(1) ) ) / grid.dy();
real_type u = ( point(2) - ( k0*grid.dz() + grid.min_coord(2) ) ) / grid.dz();
return OpenTissue::math::trillinear( d000, d001, d010, d011, d100, d101, d110, d111, s, t, u );
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_VALUE_AT_POINT_H
#endif

View File

@@ -0,0 +1,54 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_VOXEL_PLANE_CLIP_H
#define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_VOXEL_PLANE_CLIP_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace grid
{
/**
* Clip a voxelgrid against a plane.
* @param voxels Input voxel grid.
* @param plane Plane to clip against.
* @param below Upon return, contains grid of all voxels below plane.
* @param above Upon return, contains grid of all voxels above plane.
*/
template < typename grid_type, typename plane_type >
inline void voxel_plane_clip(
grid_type const& voxels
, plane_type const& plane
, grid_type & below
, grid_type & above
)
{
typedef typename grid_type::value_type value_type;
typedef typename grid_type::const_index_iterator const_index_iterator;
const_index_iterator voxel;
for ( voxel=voxels.begin(); voxel!=voxels.end(); ++voxel )
{
if ( plane.signed_distance( voxel.get_coord() ) >= 0 )
{
above( voxel.get_index() ) = voxels( voxel.get_index() );
below( voxel.get_index() ) = value_type(0);
}
else
{
below( voxel.get_index() ) = voxels( voxel.get_index() );
above( voxel.get_index() ) = value_type(0);
}
}
}
} // namespace grid
} // namespace OpenTissue
// OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GRID_VOXEL_PLANE_CLIP_H
#endif

View File

@@ -0,0 +1,74 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_T4MESH_CORE_ACCESS_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_T4MESH_CORE_ACCESS_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace t4mesh
{
class t4mesh_core_access
{
public:
template< typename feature_type, typename index_type>
static void set_index(feature_type & f, index_type idx)
{
f.set_index(idx);
}
template< typename feature_type, typename mesh_type>
static void set_owner(feature_type & f, mesh_type * owner)
{
f.set_owner(owner);
}
template< typename tetrahedron_type, typename index_type>
static void set_node0(tetrahedron_type & tetrahedron, index_type idx)
{
tetrahedron.set_node0(idx);
}
template< typename tetrahedron_type, typename index_type>
static void set_node1(tetrahedron_type & tetrahedron, index_type idx)
{
tetrahedron.set_node1(idx);
}
template< typename tetrahedron_type, typename index_type>
static void set_node2(tetrahedron_type & tetrahedron, index_type idx)
{
tetrahedron.set_node2(idx);
}
template< typename tetrahedron_type, typename index_type>
static void set_node3(tetrahedron_type & tetrahedron, index_type idx)
{
tetrahedron.set_node3(idx);
}
template< typename node_type, typename index_type>
static void tetrahedra_push_back(node_type & node, index_type idx)
{
node.tetrahedra_push_back(idx);
}
template< typename node_type, typename index_type>
static void tetrahedra_remove(node_type & node, index_type idx)
{
node.tetrahedra_remove(idx);
}
};
} // namespace trimesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_T4MESH_CORE_ACCESS_H
#endif

View File

@@ -0,0 +1,70 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_T4MESH_DEFAULT_POINT_CONTAINER_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_T4MESH_DEFAULT_POINT_CONTAINER_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace t4mesh
{
/**
* Default Point Container.
* This utility class can be used to make the coordniates of the nodes in
* a tetrahedra mesh appear as a point container, i.e. as though the coordinates
* are stored as
*
* std::vector<vector3_type> coordinates;
*
* and accesses as
*
* coordinates[node->idx()]
*
* instead of
*
* node->m_coord
*
* Many algoritms in OpenTissue have been implemented in such a way that they
* do not rely on nodes to have a m_coord member. Instead coordinates are passed
* as point containers. This utility make it convenient to use these algorithms
* on nodes where coordinates are stored in m_coord member.
*
*/
template<typename M>
struct default_point_container
{
typedef M mesh_type;
typedef typename mesh_type::math_types math_types;
typedef typename math_types::vector3_type value_type;
mesh_type * m_mesh;
default_point_container(mesh_type * mesh) : m_mesh(mesh) {}
value_type & operator[] (unsigned int const & idx)
{
return m_mesh->node(idx)->m_coord;
}
value_type const & operator[] (unsigned int const & idx)const
{
return m_mesh->node(idx)->m_coord;
}
void clear(){}
size_t size() const {return m_mesh->size_nodes();}
void resize(size_t){}
};
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_T4MESH_DEFAULT_POINT_CONTAINER_H
#endif

View File

@@ -0,0 +1,38 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_DEFAULT_TRAITS_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_DEFAULT_TRAITS_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace t4mesh
{
template<typename math_types>
class DefaultNodeTraits
{
public:
typedef typename math_types::vector3_type vector3_type;
typedef typename math_types::real_type real_type;
vector3_type m_coord; ///< Default Coordinate of tetramesh node.
};
class DefaultTetrahedronTraits { };
class DefaultT4EdgeTraits { };
class DefaultT4FaceTraits { };
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_DEFAULT_TRAITS_H
#endif

View File

@@ -0,0 +1,153 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_T4BOUNDARY_FACES_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_T4BOUNDARY_FACES_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <list>
#include <cassert>
namespace OpenTissue
{
namespace t4mesh
{
/**
* t4mesh Face.
*/
template<typename M, typename F>
class T4Face : public F
{
public:
typedef M mesh_type;
typedef F face_traits;
typedef T4Face<M,F> face_type;
typedef typename mesh_type::index_type index_type;
protected:
index_type m_idx0; ///< First node index.
index_type m_idx1; ///< Second node index.
index_type m_idx2; ///< Third node index.
public:
T4Face()
: m_idx0(-1)
, m_idx1(-1)
, m_idx2(-1)
{}
T4Face(index_type const & index0, index_type const & index1, index_type const & index2)
: m_idx0(index0)
, m_idx1(index1)
, m_idx2(index2)
{}
public:
const index_type & idx0() const { return m_idx0; }
const index_type & idx1() const { return m_idx1; }
const index_type & idx2() const { return m_idx2; }
};
/**
* Tetrahedra Mesh Boundary Faces.
* Note that if subsequent changes are made to the t4mesh are not reflected in
* the faces stored in this class. Meaning that a new face-queury
* must be initiated everytime the t4mesh changes its topology.
*
* Example of usage:
*
* typedef t4mesh<...> MyMeshType;
* MyMeshType mymesh;
* ...
* class MyFaceTraits : public DefaultFaceTraits
* {
* public:
* Color m_color;
* ...
* };
* typedef T4BoundaryFaces<MyMeshType,MyFaceTraits> MyBoundaryFaces;
* MyBoundaryFaces bounday(mymesh);
* for(MyBoundaryFaces::face_iterator face=boundary.begin();face!=boundary.end();++face)
* {
* face->m_color = Color::white;
* std::cout << face->idx0() << std::endl;
* }
*/
template<class M,typename F>
class T4BoundaryFaces
{
public:
typedef M mesh_type;
typedef F face_traits;
typedef T4Face<M,F> face_type;
typedef std::list<face_type> face_container;
typedef typename face_container::iterator face_iterator;
typedef typename face_container::const_iterator const_face_iterator;
protected:
face_container m_faces; ///< Container of extrated boundary faces.
public:
face_iterator begin() { return m_faces.begin(); }
face_iterator end() { return m_faces.end(); }
const_face_iterator begin() const { return m_faces.begin(); }
const_face_iterator end() const { return m_faces.end(); }
public:
/**
* Default Constructor.
* Constructs an empty set of boundary faces.
*/
T4BoundaryFaces()
: m_faces()
{}
/**
* Specialezed Constructor
* Traverses the tetrahedral mesh, and extracts all boundary faces. A boundary
* face is a face that only have one neighboring tetrahedron. A face inside
* the tetrahedral mesh will have exactly two neighboring tetrahedra.
*
* Face node indices are given in CCW order.
*
* @param mesh The tetrahedral mesh from which boundary
* faces are extracted.
*/
T4BoundaryFaces(mesh_type & mesh)
: m_faces()
{
typename mesh_type::tetrahedron_iterator tetrahedron;
for( tetrahedron = mesh.tetrahedron_begin(); tetrahedron != mesh.tetrahedron_end(); ++tetrahedron)
{
if(tetrahedron->jkm()==mesh.tetrahedron_end())
m_faces.push_back(face_type(tetrahedron->j()->idx(),tetrahedron->k()->idx(),tetrahedron->m()->idx()));
if(tetrahedron->ijm()==mesh.tetrahedron_end())
m_faces.push_back(face_type(tetrahedron->i()->idx(),tetrahedron->j()->idx(),tetrahedron->m()->idx()));
if(tetrahedron->kim()==mesh.tetrahedron_end())
m_faces.push_back(face_type(tetrahedron->k()->idx(),tetrahedron->i()->idx(),tetrahedron->m()->idx()));
if(tetrahedron->ikj()==mesh.tetrahedron_end())
m_faces.push_back(face_type(tetrahedron->i()->idx(),tetrahedron->k()->idx(),tetrahedron->j()->idx()));
}
}
};
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_T4BOUNDARY_FACES_H
#endif

View File

@@ -0,0 +1,219 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_T4EDGES_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_T4EDGES_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <list>
#include <cassert>
namespace OpenTissue
{
namespace t4mesh
{
/**
* t4mesh Edge.
* An edge is uniquely defined by the indices of its two end nodes.
* The order of indices do not matter.
*/
template<typename M, typename E>
class T4Edge : public E
{
public:
typedef M mesh_type;
typedef E edge_traits;
typedef T4Edge<M,E> edge_type;
typedef typename mesh_type::index_type index_type;
protected:
index_type m_idxA; ///< Index to first node.
index_type m_idxB; ///< Index to second node.
public:
T4Edge()
: m_idxA(-1)
, m_idxB(-1)
{}
T4Edge(index_type const & indexA, index_type const & indexB)
: m_idxA(indexA)
, m_idxB(indexB)
{}
public:
index_type const & idxA() const { return m_idxA; }
index_type const & idxB() const { return m_idxB; }
bool operator==(edge_type const & edge) const
{
if(m_idxA==edge.idxA() && m_idxB==edge.idxB())
return true;
if(m_idxB==edge.idxA() && m_idxA==edge.idxB())
return true;
return false;
}
bool operator!=(edge_type const & edge)const{ return !((*this)==edge); }
};
/**
* Tetrahedra Mesh Edges.
* Edges are not represented explicitly in a t4mesh, only nodes and tetrahedra
* are representated. Thus this class extracts all unique edges from a t4mesh, by
* traversing it and generating explicit edges.
*
* Note that if subsequent changes are made to the t4mesh, the edge changes are
* not reflected by the edges stored in this class. Meaning that a new edge-queury
* must be initiated everytime the t4mesh changes its topology.
*
*/
template<class M, typename E >
class T4Edges
{
public:
typedef M mesh_type;
typedef E edge_traits;
typedef T4Edge<M,E> edge_type;
typedef typename mesh_type::index_type index_type;
typedef std::list<edge_type> edge_container;
typedef typename edge_container::iterator edge_iterator;
typedef typename edge_container::const_iterator const_edge_iterator;
protected:
typedef enum{white,grey,black} color_type;
typedef std::vector<color_type> color_container;
typedef typename mesh_type::node_type node_type;
typedef typename node_type::tetrahedron_circulator tetrahedron_type;
typedef std::list<node_type*> work_queue;
protected:
edge_container m_edges;
public:
edge_iterator begin() { return m_edges.begin(); }
edge_iterator end() { return m_edges.end(); }
const_edge_iterator begin() const { return m_edges.begin(); }
const_edge_iterator end() const { return m_edges.end(); }
protected:
/**
* Internally used functor, needed for visiting neighboring
* nodes and extracting un-seen edges.
*/
struct VisitT4Edge
{
void visit(
index_type & idxA
, index_type & idxB
, work_queue & work
, color_container & colors
, edge_container & edges
, mesh_type & mesh
)
{
if(idxA==idxB)//--- self-loop, ignore it
return;
//std::cout << "\tvisting:" <<idxB << " : color = " << colors[idxB] << std::endl;
if(colors[idxB]==white)
{
colors[idxB] = grey;
work.push_back(&(*(mesh.node(idxB))));
}
if(colors[idxB]!=black)
{
edges.push_back(edge_type(idxA,idxB));
}
}
};
public:
T4Edges(){}
/**
* Specialized Constructor.
* This constructor traverses the specified mesh and extracts all edges.
*/
T4Edges(mesh_type & mesh)
{
index_type idxA,idxB;
color_container colors(mesh.size_nodes());
std::fill(colors.begin(),colors.end(),white);
node_type * node = &(*(mesh.node(0)));
colors[0]=grey;
work_queue work;
work.push_back(node);
while(!work.empty())
{
node = work.back();
work.pop_back();
idxA = node->idx();
assert(colors[idxA] == grey || !"T4Edges(mesh): Encounted non-greay node");
//std::cout << idxA << " : color = " << colors[idxA] << std::endl;
std::list<index_type> neighbors;
for(tetrahedron_type T = node->begin();T!=node->end();++T)
{
idxB = T->i()->idx();
if(idxB != idxA)
neighbors.push_back(idxB);
idxB = T->j()->idx();
if(idxB != idxA)
neighbors.push_back(idxB);
idxB = T->k()->idx();
if(idxB != idxA)
neighbors.push_back(idxB);
idxB = T->m()->idx();
if(idxB != idxA)
neighbors.push_back(idxB);
}
neighbors.sort();
neighbors.unique();
for(typename std::list<index_type>::iterator n = neighbors.begin();n!=neighbors.end();++n)
VisitT4Edge().visit(idxA, *n ,work,colors,m_edges,mesh);
//for(tetrahedron_type T = node->begin();T!=node->end();++T)
//{
// idxB = T->i()->idx();
// VisitT4Edge().visit(idxA,idxB,work,colors,m_edges,mesh);
// idxB = T->j()->idx();
// VisitT4Edge().visit(idxA,idxB,work,colors,m_edges,mesh);
// idxB = T->k()->idx();
// VisitT4Edge().visit(idxA,idxB,work,colors,m_edges,mesh);
// idxB = T->m()->idx();
// VisitT4Edge().visit(idxA,idxB,work,colors,m_edges,mesh);
//}
colors[idxA] = black;
}
};
};
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_T4EDGES_H
#endif

View File

@@ -0,0 +1,202 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_T4MESH_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_T4MESH_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/t4mesh/t4mesh_t4node.h>
#include <OpenTissue/core/containers/t4mesh/t4mesh_t4tetrahedron.h>
#include <OpenTissue/core/containers/t4mesh/t4mesh_core_access.h>
#include <OpenTissue/core/math/math_constants.h>
#include <vector>
#include <list>
#include <cassert>
namespace OpenTissue
{
namespace t4mesh
{
namespace detail
{
/**
* Basic (Simple) Tetrahedra Mesh.
*
* This tetrahedra mesh data structure is designed specially for
* two purposes: It should maintain a valid topology of the mesh
* at all times, that is the connectivity of nodes and tetrahedra
* are always valid.
*
* The other purpose is to make sure that the global indexing of
* nodes (0..N-1) and tetrahedra (0..T-1) always is a compact range
* starting from zero to the maximum number minus one.
*
* Obviously removing entities (nodes or tetrahedra) alters the global
* index ranges, thus end users can not trust previously stored indices
* of entities in their own apps.
*
* The mesh takes three template arguments. The first specifies the
* math_types used in the mesh. The following two arguments are node
* traits and tetrahedron traits respectively.
*/
template<
typename M
, typename N
, typename T
>
class T4Mesh
{
public:
typedef M math_types;
typedef N node_traits;
typedef T tetrahedron_traits;
typedef T4Mesh<M,N,T> mesh_type;
typedef T4Node<mesh_type> node_type;
typedef T4Tetrahedron<mesh_type> tetrahedron_type;
typedef size_t index_type;
/**
* Undefined index value.
*
* @return An index value that means that the index value is undefined. The
* largest possible value of the index type is used for this purpose.
*/
static index_type const & undefined()
{
static index_type value = FLT_MAX;//math::detail::highest<index_type>();
return value;
}
protected:
typedef std::vector< node_type > node_container;
typedef std::vector< tetrahedron_type > tetrahedra_container;
public:
node_container m_nodes; ///< Internal node storage.
tetrahedra_container m_tetrahedra; ///< Internal tetrahedra storage.
public:
public:
T4Mesh()
: m_nodes()
, m_tetrahedra()
{}
T4Mesh( T4Mesh const & cpy)
{
*this = cpy;
}
public:
void clear()
{
m_nodes.clear();
m_tetrahedra.clear();
}
public:
/**
* Add New Node.
* New node will have index value equal to number of nodes prior to insertion.
*
* @return A iterator to the new node
*/
void insert()
{
m_nodes.push_back( node_type() );
node_type & nd = m_nodes.back();
t4mesh_core_access::set_index( nd, this->m_nodes.size()-1 );
t4mesh_core_access::set_owner( nd, this );
}
/**
* Overloaded insert method for tetrahedron, support index-based insertion.
*
* This is a bit slower than using the iterator-based insertion method directly.
* But it makes it easier to code....
*
*/
void insert(
index_type i,
index_type j,
index_type k,
index_type m
)
{
// assert(find(i,j,k,m)==tetrahedron_end() || !"T4Mesh::insert(): Tetrahedron already exists in mesh");
m_tetrahedra.push_back( tetrahedron_type() );
tetrahedron_type & t = m_tetrahedra.back();
t4mesh_core_access::set_index( t, m_tetrahedra.size() - 1 );
t4mesh_core_access::set_owner( t, this );
t4mesh_core_access::set_node0( t, i );
t4mesh_core_access::set_node1( t, j );
t4mesh_core_access::set_node2( t, k );
t4mesh_core_access::set_node3( t, m );
t4mesh_core_access::tetrahedra_push_back( m_nodes[i], t.idx() );
t4mesh_core_access::tetrahedra_push_back( m_nodes[j], t.idx() );
t4mesh_core_access::tetrahedra_push_back( m_nodes[k], t.idx() );
t4mesh_core_access::tetrahedra_push_back( m_nodes[m], t.idx() );
//return tetrahedron_iterator(m_tetrahedra, t.idx());
}
/**
* Erase Tetrahedron at specified Position.
*
* @param where
*
* @return
*/
index_type erase(index_type& where)
{
index_type last = m_tetrahedra.size()-1;
if (where != last)
{
this->swap(where,last);
}
this->unlink(last);
//--- This might be a bit stupid, it would
//--- proberly be better to keep track of last unused
//--- entry and only resize vector when there is no
//--- more space
m_tetrahedra.pop_back();
return where;
}
protected:
protected:
};
} // namespace detail
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_T4MESH_H
#endif

View File

@@ -0,0 +1,138 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_T4NODE_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_T4NODE_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <list>
#include <cassert>
namespace OpenTissue
{
namespace t4mesh
{
template< typename mesh_type_>
class T4Node : public mesh_type_::node_traits
{
public:
typedef mesh_type_ mesh_type;
typedef typename mesh_type::node_type node_type;
typedef typename mesh_type::tetrahedron_type tetrahedron_type;
typedef typename mesh_type::index_type index_type;
typedef std::list<index_type> tetrahedra_index_container;
typedef typename tetrahedra_index_container::iterator tetrahedra_idx_iterator;
protected:
index_type m_idx; ///< Global index of node
mesh_type * m_owner; ///< Pointer to mesh which the node belongs to.
tetrahedra_index_container m_tetrahedra; ///< Indices of tetrahedra this node is part of.
private:
friend class t4mesh_core_access;
void set_index(index_type idx) { m_idx = idx; }
void set_owner(mesh_type * owner) { m_owner = owner; }
void tetrahedra_push_back(index_type idx) { m_tetrahedra.push_back(idx); }
void tetrahedra_remove(index_type idx) { m_tetrahedra.remove(idx); }
public:
class tetrahedron_circulator
{
private:
node_type * m_node; ///< A pointer to the node
tetrahedra_idx_iterator m_it; ///< An ``local'' iterator to the tetrahedron index, indicating current tetrahedron of this iterator.
public:
tetrahedron_circulator()
: m_node( 0 )
, m_it( 0 )
{}
tetrahedron_circulator( node_type * node, tetrahedra_idx_iterator pos)
: m_node( node )
, m_it( pos )
{
assert(m_node || !"tetrahedron_circulator() : node was null");
assert(m_node->m_owner || !"tetrahedron_circulator(..) : owner was null");
}
bool operator== ( tetrahedron_circulator const & other ) const
{
return ( m_node == other.m_node && m_it == other.m_it );
}
bool operator!= ( tetrahedron_circulator const & other ) const
{
return !( *this == other);
}
tetrahedron_type & operator*()
{
assert(m_node || !"tetrahedron_circulator::* : node was null");
assert(m_node->m_owner || !"tetrahedron_circulator::* : owner was null");
return *(m_node->m_owner->tetrahedron(*m_it));
}
tetrahedron_type * operator->()
{
assert(m_node || !"tetrahedron_circulator::-> : node was null");
assert(m_node->m_owner || !"tetrahedron_circulator::-> : owner was null");
return &(*(m_node->m_owner->tetrahedron(*m_it)));
}
tetrahedron_circulator & operator++()
{
assert(m_node || !"tetrahedron_circulator::++ : node was null");
assert(m_node->m_owner || !"tetrahedron_circulator::++ : owner was null");
++m_it;
return *this;
}
};
tetrahedron_circulator begin() { return tetrahedron_circulator( this, m_tetrahedra.begin() ); }
tetrahedron_circulator end() { return tetrahedron_circulator( this, m_tetrahedra.end() ); }
/**
* Get Number of Tetrahedra.
*
* @return The number of tetrahedra that this node is part of. If
* zero it means the node is an isolated node.
*/
size_t size_tetrahedra() const { return m_tetrahedra.size(); }
bool isolated() const { return m_tetrahedra.empty(); }
public:
T4Node()
: m_idx( mesh_type::undefined() )
, m_owner(0)
, m_tetrahedra()
{}
public:
index_type idx() const { return m_idx; }
mesh_type * owner() { return m_owner; }
mesh_type const * owner() const { return m_owner; }
};
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_T4NODE_H
#endif

View File

@@ -0,0 +1,105 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_T4TETRAHEDRON_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_T4TETRAHEDRON_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <cassert>
namespace OpenTissue
{
namespace t4mesh
{
template< typename mesh_type_>
class T4Tetrahedron : public mesh_type_::tetrahedron_traits
{
public:
typedef mesh_type_ mesh_type;
typedef typename mesh_type::node_type node_type;
typedef typename mesh_type::tetrahedron_type tetrahedron_type;
typedef typename mesh_type::index_type index_type;
index_type m_idx; ///< Global index of tetrahedron
mesh_type * m_owner; ///< Pointer to mesh which the node belongs to.
index_type m_nodes[4]; ///< Global index of node i,j,k and m
private:
friend class t4mesh_core_access;
void set_index(index_type idx) { m_idx = idx; }
void set_owner(mesh_type * owner) { m_owner = owner; }
void set_node0(index_type idx) { m_nodes[0] = idx; }
void set_node1(index_type idx) { m_nodes[1] = idx; }
void set_node2(index_type idx) { m_nodes[2] = idx; }
void set_node3(index_type idx) { m_nodes[3] = idx; }
public:
#ifdef TODO_ERWIN
T4Tetrahedron()
: m_idx( mesh_type::undefined() )
, m_owner(0)
{
this->m_nodes.assign( mesh_type::undefined() );
}
#endif
public:
node_type* node(index_type idx)
{
return &m_owner->m_nodes[m_nodes[idx]];
}
const node_type* node(index_type idx) const
{
return &m_owner->m_nodes[m_nodes[idx]];
}
node_type* i()
{
return node(0);
}
node_type* j()
{
return node(1);
}
node_type* k()
{
return node(2);
}
node_type* m()
{
return node(3);
}
index_type idx() const { return m_idx; }
index_type node_idx(index_type const & local_idx) const
{
assert(0<=local_idx);
assert(local_idx<=3);
return m_nodes[local_idx];
}
mesh_type * owner() { return m_owner; }
mesh_type const * owner() const { return m_owner; }
};
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_T4TETRAHEDRON_H
#endif

View File

@@ -0,0 +1,114 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_BLOCK_GENERATOR_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_BLOCK_GENERATOR_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
namespace OpenTissue
{
namespace t4mesh
{
/**
* t4mesh Block Generator.
*
* @param I The number of blocks along x axis.
* @param J The number of blocks along y axis.
* @param K The number of blocks along z axis.
* @param block_width The edgelength of the blocks along x-axis.
* @param block_height The edgelength of the blocks along x-axis.
* @param block_depth The edgelength of the blocks along x-axis.
* @param mesh A generic t4mesh, which upon return holds the generated mesh.
*/
template < typename real_type, typename t4mesh_type >
void generate_blocks(
unsigned int const & I
, unsigned int const & J
, unsigned int const & K
, real_type const & block_width
, real_type const & block_height
, real_type const & block_depth
, t4mesh_type & mesh
)
{
mesh.clear();
unsigned int numVertices = (I + 1) * (J + 1) * (K + 1);
for (unsigned int i=0; i<numVertices; ++i)
mesh.insert();
int node_it = 0;
for (unsigned int x = 0; x <= I; ++x)
{
for (unsigned int y = 0; y <= J; ++y)
{
for (unsigned int z = 0; z <= K; ++z)
{
mesh.m_nodes[node_it].m_coord(0) = block_width*x;
mesh.m_nodes[node_it].m_coord(2) = block_depth*y;
mesh.m_nodes[node_it].m_coord(1) = block_height*z;
++node_it;
}
}
}
for (unsigned int i = 0; i < I; ++i)
{
for (unsigned int j = 0; j < J; ++j)
{
for (unsigned int k = 0; k < K; ++k)
{
// For each block, the 8 corners are numerated as:
// 4*-----*7
// /| /|
// / | / |
// 5*-----*6 |
// | 0*--|--*3
// | / | /
// |/ |/
// 1*-----*2
int p0 = (i * (J + 1) + j) * (K + 1) + k;
int p1 = p0 + 1;
int p3 = ((i + 1) * (J + 1) + j) * (K + 1) + k;
int p2 = p3 + 1;
int p7 = ((i + 1) * (J + 1) + (j + 1)) * (K + 1) + k;
int p6 = p7 + 1;
int p4 = (i * (J + 1) + (j + 1)) * (K + 1) + k;
int p5 = p4 + 1;
// Ensure that neighboring tetras are sharing faces
if ((i + j + k) % 2 == 1)
{
mesh.insert(p1,p2,p6,p3);
mesh.insert(p3,p6,p4,p7);
mesh.insert(p1,p4,p6,p5);
mesh.insert(p1,p3,p4,p0);
mesh.insert(p1,p6,p4,p3);
}
else
{
mesh.insert(p2,p0,p5,p1);
mesh.insert(p2,p7,p0,p3);
mesh.insert(p2,p5,p7,p6);
mesh.insert(p0,p7,p5,p4);
mesh.insert(p2,p0,p7,p5);
}
}
}
}
};
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_BLOCK_GENERATOR_H
#endif

View File

@@ -0,0 +1,280 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_MESH_COUPLING_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_MESH_COUPLING_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/collision/spatial_hashing/spatial_hashing.h>
namespace OpenTissue
{
namespace t4mesh
{
namespace mesh_coupling
{
template<typename surface_mesh,typename volume_mesh>
class collision_policy
{
public:
typedef typename surface_mesh::vertex_type vertex_type;
typedef typename volume_mesh::tetrahedron_type tetrahedron_type;
typedef double real_type;
typedef math::Vector3<real_type> point_type;
typedef vertex_type* data_type;
typedef tetrahedron_type query_type;
typedef OpenTissue::spatial_hashing::GridHashFunction hash_function;
typedef OpenTissue::spatial_hashing::Grid< point_type, math::Vector3<int>, data_type, hash_function> hash_grid;
class result_type
{
public:
vertex_type * m_data;
tetrahedron_type * m_query;
real_type m_w0;
real_type m_w1;
real_type m_w2;
real_type m_w3;
};
typedef std::list<result_type> result_container;
public:
point_type position(data_type const & data) const
{
return data->m_coord;
}
point_type min_coord(query_type const & query) const
{
using std::min;
point_type & p0 = query.i()->m_coord;
point_type & p1 = query.j()->m_coord;
point_type & p2 = query.k()->m_coord;
point_type & p3 = query.m()->m_coord;
return min( p0, min( p1 , min( p2, p3) ) );
}
point_type max_coord(query_type const & query) const
{
using std::max;
point_type & p0 = query.i()->m_coord;
point_type & p1 = query.j()->m_coord;
point_type & p2 = query.k()->m_coord;
point_type & p3 = query.m()->m_coord;
return max( p0, max( p1 , max( p2, p3) ) );
}
void reset(result_container & results) { results.clear(); };
void report(data_type const & data, query_type const & query,result_container & results)
{
//--- First we do a quick rejection test. If the vertex is allready reported then simply ignore it!!!
if(data->m_tag == 1)
return;
point_type & pi = query.i()->m_coord;
point_type & pj = query.j()->m_coord;
point_type & pk = query.k()->m_coord;
point_type & pm = query.m()->m_coord;
point_type & p = data->m_coord;
real_type delta = 10e-5;
real_type lower = - delta;
real_type upper = 1.+ delta;
result_type result;
OpenTissue::geometry::barycentric_algebraic(pi,pj,pk,pm,p,result.m_w0,result.m_w1,result.m_w2,result.m_w3);
if(
(result.m_w0>lower)&&(result.m_w0<upper)
&&
(result.m_w1>lower)&&(result.m_w1<upper)
&&
(result.m_w2>lower)&&(result.m_w2<upper)
&&
(result.m_w3>lower)&&(result.m_w3<upper)
)
{
data->m_tag = 1;
result.m_data = const_cast<vertex_type*>( data );
result.m_query = const_cast<tetrahedron_type*>( &query );
results.push_back( result );
return;
}
}
};
/**
* Bind Mesh Surface to t4mesh.
*
*
* @param M A surface mesh that should be bound to a volume mesh.
* @param V A T4Mesh it is implicitly assumed that node traits have a
* real_type and vector3_type (these are defined in the
* default node traits).
*/
template<typename surface_mesh, typename volume_mesh, typename point_container,typename index_container>
void bind_surface (surface_mesh & M,volume_mesh & V,point_container & barycentric,index_container & bind_indices)
{
//---
//--- The main idea behind mesh coupling is to create a multiresolution for the
//--- animataion. The idea is to separate the visual geometry from the geometry
//--- used to compute the dynamics. This allows one to use highly detailed visual
//--- representation of objects, while using a computational low cost coarse volume
//--- mesh for the computing the dynamcis.
//---
//--- A technique for doing this is callled mesh coupling or cartoon meshing. Below
//--- we describe how it is used together with tetrahedral meshes. It is however a
//--- general approach and can be used with other types of geometries, FFD lattices
//--- are probably anohter very common example on mesh coupling.
//---
//--- When using Mesh Coulping the first step is to bind the vertices of the surface
//--- mesh to the tetrahedral elements of the volume mesh.
//---
//--- Here we use a spatial hashing algorithm to find vertex tetrahedron pairs, where
//--- the vertex is embedded inside the tetrahedron. The actual test is done by first
//--- computing the barycentric coordinates of the vertex with respect to a tetrahedron
//--- in question.
//---
//--- If each barycentric coordinate is greather than equal to zero and less than equal
//--- to one then the vertex is embedded in the tetrahedron. In pratice we need to apply
//--- treshold testing to counter numerical precision problems. It may therefor happen
//--- that vertices lying close to a face of a tetrahedron gets reported twice. Once of
//--- the tetrahedron embedding it and once for the neighboring tetetrahedron. The same
//--- happens if the vertex lies exactly on a face.
//---
//--- Therefore, we firstdo a quick rejection test. If the vertex is allready reported
//--- then simply ignore it!!!
//---
//--- Before rendering each frame, we must update the vertex positions to reflect the
//--- underlying deformation of the tetrahedral mesh. This is done using the barycentric
//--- coordinates, such that the new vertex position is given by
//---
//--- c = w0 p0 + w1 p1 + w2 p2 + w3 p3
//---
//--- Where p0, p1 ,p2, and p3 are the nodal coordinates of the tetrahedron which
//--- the vertex was bounded to.
//---
//--- If stiffness warping is used, the element rotation, Re, can be
//--- used to update the undeformed vertex normal, n0, into the deformed
//--- vertex normal, n, by,
//---
//--- n = Re n0
//---
//--- Often a tetrahedra mesh is used with a conservative coverage of the surface mesh.
//--- That means one is guaranteed that all vertices of the surface mesh are embedded
//--- inside one unique tetrahedron. However, mesh coupling can be used in cases where
//--- one only have a partial coverage. The solution is to bind a vertex to the
//--- closest tetrahedron. Eventhough the vertex lies outside the tetrahedra mesh, the
//--- barycentric coordinates extend the deformation of the tetrahedra mesh beyond
//--- its surface.
//---
typedef collision_policy<surface_mesh,volume_mesh> policy;
typedef OpenTissue::spatial_hashing::PointDataQuery<typename policy::hash_grid, policy> point_query_type;
typename policy::result_container results;
point_query_type point_query;
point_query.auto_init_settings(V.tetrahedron_begin(),V.tetrahedron_end());
//--- perform query
mesh::clear_vertex_tags(M);
std::vector<typename surface_mesh::vertex_type*> vertex_ptr_container(M.size_vertices());
unsigned int i = 0;
for(typename surface_mesh::vertex_iterator v= M.vertex_begin();v!=M.vertex_end();++v,++i)
{
vertex_ptr_container[i] = &(*v);
}
point_query(
vertex_ptr_container.begin()
, vertex_ptr_container.end()
, V.tetrahedron_begin()
, V.tetrahedron_end()
, results
, typename point_query_type::all_tag()
);
unsigned int size = static_cast<unsigned int>( results.size() );
barycentric.resize(size);
bind_indices.resize(size);
typename policy::result_container::iterator Rbegin = results.begin();
typename policy::result_container::iterator Rend = results.end();
for(typename policy::result_container::iterator R = Rbegin;R!=Rend;++R)
{
unsigned int i = static_cast<unsigned int>( R->m_data->get_handle().get_idx() );
barycentric[i](0) = R->m_w1;
barycentric[i](1) = R->m_w2;
barycentric[i](2) = R->m_w3;
bind_indices[i] = R->m_query->idx();
}
};
/**
* Update Surface Mesh.
*
*
* @param M A surface mesh that is bound to a volume mesh.
* @param V The volume mesh that the surface is bound to. It
* is implicitly assumed that the node traits define
* a real_type and vector3_type ((these are defined in
* the default node traits).
* @param barycentric
* @param bind_info
*/
template<typename surface_mesh, typename volume_mesh, typename point_container,typename index_container>
void update_surface (
surface_mesh & M,
volume_mesh & V,
point_container const & barycentric,
index_container const & bind_info
)
{
typename surface_mesh::vertex_iterator begin = M.vertex_begin();
typename surface_mesh::vertex_iterator end = M.vertex_end();
typedef typename volume_mesh::tetrahedron_iterator tetrahedron_iterator;
typedef typename volume_mesh::node_type node_type;
typedef typename node_type::real_type real_type;
typedef typename node_type::vector3_type vector3_type;
for( typename surface_mesh::vertex_iterator v = begin; v!=end; ++v)
{
unsigned int i = static_cast<unsigned int>( v->get_handle().get_idx() );
tetrahedron_iterator T = V.tetrahedron( bind_info[i] );
real_type w1 = barycentric[i](0);
real_type w2 = barycentric[i](1);
real_type w3 = barycentric[i](2);
real_type w0 = 1 - w1 - w2 - w3;
vector3_type & p0 = T->i()->m_coord;
vector3_type & p1 = T->j()->m_coord;
vector3_type & p2 = T->k()->m_coord;
vector3_type & p3 = T->m()->m_coord;
v->m_coord = p0*w0 + p1*w1 + p2*w2 + p3*w3;
}
};
} // namespace mesh_coupling
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_MESH_COUPLING_H
#endif

View File

@@ -0,0 +1,48 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_TETGEN_CONSTRAINED_DELAUNAY_TRIANGULATION_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_TETGEN_CONSTRAINED_DELAUNAY_TRIANGULATION_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/t4mesh/util/t4mesh_tetgen_mesh_lofter.h>
namespace OpenTissue
{
namespace t4mesh
{
namespace tetgen
{
/**
* Constrained Delaunay Tetrahedralization Routine.
* - uses TetGen to create the resulting tetrahedal mesh
*
* @param polymesh A poly mesh, which holds a closed two-manifold.
* @param t4mesh A generic t4mesh, which upon return holds the generated tetrahedal mesh.
*
* @return if succesfull then the return value is true otherwise it is false.
*/
template<typename t4mesh_type, typename polymesh_type>
inline bool constrained_delaunay_tetrahedralization(const polymesh_type& polymesh, t4mesh_type & t4mesh)
{
OpenTissue::t4mesh::mesh_lofter_settings config;
config.m_intermediate_file = "tmp";
config.m_quality_ratio = 0.0;
config.m_maximum_volume = 0.0;
config.m_quiet_output = true;
return OpenTissue::t4mesh::mesh_lofter(t4mesh, polymesh, config);
}
} // namespace tetgen
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_TETGEN_CONSTRAINED_DELAUNAY_TRIANGULATION_H
#endif

View File

@@ -0,0 +1,128 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_TETGEN_MESH_LOFTER_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_TETGEN_MESH_LOFTER_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/mesh/common/io/mesh_tetgen_write.h>
#include <OpenTissue/core/containers/mesh/polymesh/util/polymesh_is_manifold.h>
#include <OpenTissue/core/containers/t4mesh/io/t4mesh_tetgen_read.h>
#include <TetGen/tetgen.h>
#include <cmath>
#include <string>
#include <sstream>
#include <iostream>
namespace OpenTissue
{
namespace t4mesh
{
struct mesh_lofter_settings
{
mesh_lofter_settings()
: m_quality_ratio(2./*std::sqrt(2.)*/)
, m_maximum_volume(0.)
, m_intermediate_file("")
, m_quiet_output(false)
, m_verify_input(false)
{}
double m_quality_ratio; ///< quality t4mesh is issued if > 0. A minimum radius-edge ratio may be specifyed (default 2.0).
double m_maximum_volume; ///< max volume constraints on t4mesh if > 0.
std::string m_intermediate_file; ///< use intermediate files to/fro tetget if name specified.
bool m_quiet_output; ///< keep output spam as silent as possible, great for RELEASE.
bool m_verify_input; ///< DEBUG: detects plc intersections, i.e. verify "bad" input mesh.
};
/**
* t4mesh_mesh_lofter.
* - uses tetgen to loft/extrude a closed two-manifold polymesh to a generic tetrahedal mesh
*
* @param polymesh A poly mesh, which holds a closed two-manifold.
* @param t4mesh A generic t4mesh, which upon return holds the generated tetrahedal mesh.
* @param settings The settings/configuration for TetGen, can be omitted to use the default settings.
*
*/
// TODO: Implement work-in-mem solution, thus avoid using intermediate files [MKC]
template<typename t4mesh_type, typename polymesh_type>
bool mesh_lofter(t4mesh_type& t4mesh, const polymesh_type& polymesh, const mesh_lofter_settings & settings = mesh_lofter_settings())
{
// local functions are no go in C++, thus we need to wrap them in a local class, tsk!
class local_aux
{
public:
static bool error(const std::string& text)
{
using std::operator<<;
std::cerr << "ERROR [t4mesh_mesh_lofter]:\n- " << text << std::endl;
return false;
}
};
// convenient pointer to use with TetGen
char* tmp_file = settings.m_intermediate_file.size()>0?const_cast<char*>(settings.m_intermediate_file.c_str()):NULL;
// "no tmp file" won't work check
if (!tmp_file)
return local_aux::error("current version only supports using intermediate files");
if (!is_manifold(polymesh))
return local_aux::error("polymesh is not a two-manifold");
if (tmp_file)
if (!tetgen_write(settings.m_intermediate_file+".poly", polymesh))
return local_aux::error("mesh_tetgen_write failed in writing the polymesh file: '"+settings.m_intermediate_file+".poly'");
std::stringstream tmp;
tmp << "p"; // piecewise linear complex (always)
if (settings.m_verify_input)
tmp << "d";
else {
if (settings.m_quality_ratio > 0)
tmp << "q" << settings.m_quality_ratio; // quality
if (settings.m_maximum_volume > 0)
tmp << "a" << settings.m_maximum_volume; // max volume
if (settings.m_quiet_output)
tmp << "Q"; // keep quiet :)
}
std::string txt = tmp.str().c_str();
tetgenbehavior config;
// MKC: setting vars in tetgenbehavior explicitly is too complicated, and requires a deeper knowledge of the system :(
if (!config.parse_commandline(const_cast<char*>(txt.c_str()))) // parsing a "cmd" line will set the correct vars and their dependecies.
return local_aux::error("TetGen parse_commandline failed: '"+txt+"'");
tetgenio in, out;
if (tmp_file)
if (!in.load_poly(tmp_file))
return local_aux::error("TetGen load_poly failed: '"+settings.m_intermediate_file+"'");
// let TetGen do some magic :)
tetrahedralize(&config, &in, &out);
if (out.numberoftetrahedra < 1)
return local_aux::error("TetGen tetrahedralize failed: no tetrahedra generated!");
if (tmp_file) {
out.save_elements(tmp_file);
out.save_nodes(tmp_file);
if (!tetgen_read(settings.m_intermediate_file, t4mesh))
return local_aux::error("t4mesh_tetgen_read failed in reading the data: '"+settings.m_intermediate_file+"'");
}
return true;
}
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_TETGEN_MESH_LOFTER_H
#endif

View File

@@ -0,0 +1,48 @@
#ifndef OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_TETGEN_QUALITY_TETRAHEDRALIZATION_H
#define OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_TETGEN_QUALITY_TETRAHEDRALIZATION_H
//
// OpenTissue Template Library
// - A generic toolbox for physics-based modeling and simulation.
// Copyright (C) 2008 Department of Computer Science, University of Copenhagen.
//
// OTTL is licensed under zlib: http://opensource.org/licenses/zlib-license.php
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/containers/t4mesh/util/t4mesh_tetgen_mesh_lofter.h>
namespace OpenTissue
{
namespace t4mesh
{
namespace tetgen
{
/**
* Quality Tetrahedralization Routine.
* - uses TetGen to create the resulting tetrahedal mesh
*
* @param polymesh A poly mesh, which holds a closed two-manifold.
* @param t4mesh A generic t4mesh, which upon return holds the generated tetrahedal mesh.
*
* @return if succesfull then the return value is true otherwise it is false.
*/
template<typename t4mesh_type, typename polymesh_type>
inline bool quality_tetrahedralization(const polymesh_type& polymesh, t4mesh_type & t4mesh)
{
OpenTissue::t4mesh::mesh_lofter_settings config;
config.m_intermediate_file = "tmp";
config.m_quality_ratio = 2.0;
config.m_maximum_volume = 0.0;
config.m_quiet_output = true;
return OpenTissue::t4mesh::mesh_lofter(t4mesh, polymesh, config);
}
} // namespace tetgen
} // namespace t4mesh
} // namespace OpenTissue
//OPENTISSUE_CORE_CONTAINERS_T4MESH_UTIL_T4MESH_TETGEN_QUALITY_TETRAHEDRALIZATION_H
#endif