245 lines
7.3 KiB
C++
245 lines
7.3 KiB
C++
#ifndef __VCGTEST_WALKER
|
|
#define __VCGTEST_WALKER
|
|
|
|
#include "Definitions.h"
|
|
#include "Volume.h"
|
|
|
|
// La classe Walker implementa la politica di visita del volume; conoscendo l'ordine di visita del volume
|
|
// è conveniente che il Walker stesso si faccia carico del caching dei dati utilizzati durante l'esecuzione
|
|
// degli algoritmi MarchingCubes ed ExtendedMarchingCubes, in particolare il calcolo del volume ai vertici
|
|
// delle celle e delle intersezioni della superficie con le celle. In questo esempio il volume da processare
|
|
// viene suddiviso in fette; in questo modo se il volume ha dimensione h*l*w (rispettivamente altezza,
|
|
// larghezza e profondità), lo spazio richiesto per il caching dei vertici già allocati passa da O(h*l*w)
|
|
// a O(h*l).
|
|
class Walker
|
|
{
|
|
private:
|
|
typedef int VertexIndex;
|
|
|
|
public:
|
|
Walker(const BoundingBox &bbox, const vcg::Point3i &resolution)
|
|
{
|
|
_bbox = bbox;
|
|
_resolution = resolution;
|
|
_cell_size.X() = _bbox.DimX()/_resolution.X();
|
|
_cell_size.Y() = _bbox.DimY()/_resolution.Y();
|
|
_cell_size.Z() = _bbox.DimZ()/_resolution.Z();
|
|
_slice_dimension = resolution.X()*resolution.Z();
|
|
|
|
_x_cs = new VertexIndex[ _slice_dimension ];
|
|
_y_cs = new VertexIndex[ _slice_dimension ];
|
|
_z_cs = new VertexIndex[ _slice_dimension ];
|
|
_x_ns = new VertexIndex[ _slice_dimension ];
|
|
_z_ns = new VertexIndex[ _slice_dimension ];
|
|
_v_cs = new float[_slice_dimension];
|
|
_v_ns = new float[_slice_dimension];
|
|
|
|
};
|
|
|
|
~Walker()
|
|
{}
|
|
|
|
template<class EXTRACTOR_TYPE>
|
|
void BuildMesh(Mesh &mesh, Volume &volume, EXTRACTOR_TYPE &extractor)
|
|
{
|
|
_volume = &volume;
|
|
_mesh = &mesh;
|
|
_mesh->Clear();
|
|
vcg::Point3i p1, p2;
|
|
|
|
Begin();
|
|
extractor.Initialize();
|
|
for (int j=_bbox.min.Y(); j<_bbox.max.Y()-_cell_size.Y(); j+=_cell_size.Y())
|
|
{
|
|
for (int i=_bbox.min.X(); i<_bbox.max.X()-_cell_size.X(); i+=_cell_size.X())
|
|
{
|
|
for (int k=_bbox.min.Z(); k<_bbox.max.Z()-_cell_size.Z(); k+=_cell_size.Z())
|
|
{
|
|
p1.X()=i; p1.Y()=j; p1.Z()=k;
|
|
p2.X()=i+_cell_size.X(); p2.Y()=j+_cell_size.Y(); p2.Z()=k+_cell_size.Z();
|
|
extractor.ProcessCell(p1, p2);
|
|
}
|
|
}
|
|
NextSlice();
|
|
}
|
|
extractor.Finalize();
|
|
_volume = NULL;
|
|
_mesh = NULL;
|
|
};
|
|
|
|
float V(int pi, int pj, int pk)
|
|
{
|
|
int i = pi - _bbox.min.X();
|
|
int k = pk - _bbox.min.Z();
|
|
return (pj==_current_slice) ? _v_cs[i+k*_resolution.X()] : _v_ns[i+k*_resolution.X()];
|
|
}
|
|
|
|
bool Exist(const vcg::Point3i &p1, const vcg::Point3i &p2, VertexPointer &v)
|
|
{
|
|
int i_idx = p1.X()-_bbox.min.X();
|
|
int k_idx = p2.Z()-_bbox.min.Z();
|
|
int index = i_idx+k_idx*_resolution.X();
|
|
if (p1.X()!=p2.X()) //intersezione della superficie con un Xedge
|
|
return (p1.Y()==_current_slice)? _x_cs[index]!=-1 : _x_ns[index]!=-1;
|
|
else if (p1.Y()!=p2.Y()) //intersezione della superficie con un Yedge
|
|
return _y_cs[index]!=-1;
|
|
else if (p1.Z()!=p2.Z()) //intersezione della superficie con un Zedge
|
|
return (p1.Y()==_current_slice)? _z_cs[index]!=-1 : _z_ns[index]!=-1;
|
|
|
|
assert(false); // impossibile: i due punti non erano allineati rispetto a nessuna direzione
|
|
return false;
|
|
}
|
|
|
|
void GetXIntercept(const vcg::Point3i &p1, const vcg::Point3i &p2, VertexPointer &v)
|
|
{
|
|
int i = p1.X() - _bbox.min.X();
|
|
int z = p1.Z() - _bbox.min.Z();
|
|
VertexIndex index = i+z*_resolution.X();
|
|
VertexIndex pos;
|
|
if (p1.Y()==_current_slice)
|
|
{
|
|
if ((pos=_x_cs[index])==-1)
|
|
{
|
|
_x_cs[index] = (VertexIndex) _mesh->vert.size();
|
|
pos = _x_cs[index];
|
|
Allocator::AddVertices( *_mesh, 1 );
|
|
v = &_mesh->vert[pos];
|
|
_volume->GetXIntercept(p1, p2, v);
|
|
return;
|
|
}
|
|
}
|
|
if (p1.Y()==_current_slice+_cell_size.Y())
|
|
{
|
|
if ((pos=_x_ns[index])==-1)
|
|
{
|
|
_x_ns[index] = (VertexIndex) _mesh->vert.size();
|
|
pos = _x_ns[index];
|
|
Allocator::AddVertices( *_mesh, 1 );
|
|
v = &_mesh->vert[pos];
|
|
_volume->GetXIntercept(p1, p2, v);
|
|
return;
|
|
}
|
|
}
|
|
v = &_mesh->vert[pos];
|
|
}
|
|
void GetYIntercept(const vcg::Point3i &p1, const vcg::Point3i &p2, VertexPointer &v)
|
|
{
|
|
int i = p1.X() - _bbox.min.X();
|
|
int z = p1.Z() - _bbox.min.Z();
|
|
VertexIndex index = i+z*_resolution.X();
|
|
VertexIndex pos;
|
|
if ((pos=_y_cs[index])==-1)
|
|
{
|
|
_y_cs[index] = (VertexIndex) _mesh->vert.size();
|
|
pos = _y_cs[index];
|
|
Allocator::AddVertices( *_mesh, 1);
|
|
v = &_mesh->vert[ pos ];
|
|
_volume->GetYIntercept(p1, p2, v);
|
|
}
|
|
v = &_mesh->vert[pos];
|
|
}
|
|
void GetZIntercept(const vcg::Point3i &p1, const vcg::Point3i &p2, VertexPointer &v)
|
|
{
|
|
int i = p1.X() - _bbox.min.X();
|
|
int z = p1.Z() - _bbox.min.Z();
|
|
VertexIndex index = i+z*_resolution.X();
|
|
VertexIndex pos;
|
|
if (p1.Y()==_current_slice)
|
|
{
|
|
if ((pos=_z_cs[index])==-1)
|
|
{
|
|
_z_cs[index] = (VertexIndex) _mesh->vert.size();
|
|
pos = _z_cs[index];
|
|
Allocator::AddVertices( *_mesh, 1 );
|
|
v = &_mesh->vert[pos];
|
|
_volume->GetZIntercept(p1, p2, v);
|
|
return;
|
|
}
|
|
}
|
|
if (p1.Y()==_current_slice+_cell_size.Y())
|
|
{
|
|
if ((pos=_z_ns[index])==-1)
|
|
{
|
|
_z_ns[index] = (VertexIndex) _mesh->vert.size();
|
|
pos = _z_ns[index];
|
|
Allocator::AddVertices( *_mesh, 1 );
|
|
v = &_mesh->vert[pos];
|
|
_volume->GetZIntercept(p1, p2, v);
|
|
return;
|
|
}
|
|
}
|
|
v = &_mesh->vert[pos];
|
|
}
|
|
|
|
protected:
|
|
BoundingBox _bbox;
|
|
vcg::Point3i _resolution;
|
|
vcg::Point3i _cell_size;
|
|
|
|
int _slice_dimension;
|
|
int _current_slice;
|
|
|
|
float *_v_cs; // il valore del campo campionato nella fetta di volumecorrente
|
|
float *_v_ns; // il valore del campo campionato nella prossima fetta di volume
|
|
|
|
VertexIndex *_x_cs; // indici dell'intersezioni della superficie lungo gli Xedge della fetta corrente
|
|
VertexIndex *_y_cs; // indici dell'intersezioni della superficie lungo gli Yedge della fetta corrente
|
|
VertexIndex *_z_cs; // indici dell'intersezioni della superficie lungo gli Zedge della fetta corrente
|
|
VertexIndex *_x_ns; // indici dell'intersezioni della superficie lungo gli Xedge della prossima fetta
|
|
VertexIndex *_z_ns; // indici dell'intersezioni della superficie lungo gli Zedge della prossima fetta
|
|
|
|
Mesh *_mesh;
|
|
Volume *_volume;
|
|
|
|
void NextSlice()
|
|
{
|
|
memset(_x_cs, -1, _slice_dimension*sizeof(VertexIndex));
|
|
memset(_y_cs, -1, _slice_dimension*sizeof(VertexIndex));
|
|
memset(_z_cs, -1, _slice_dimension*sizeof(VertexIndex));
|
|
|
|
std::swap(_x_cs, _x_ns);
|
|
std::swap(_z_cs, _z_ns);
|
|
std::swap(_v_cs, _v_ns);
|
|
|
|
_current_slice += _cell_size.Y();
|
|
int j = _current_slice + _cell_size.Y();
|
|
int k_idx, i_idx, index;
|
|
for (int i=_bbox.min.X(); i<_bbox.max.X(); i+=_cell_size.X())
|
|
{
|
|
i_idx = i-_bbox.min.X();
|
|
for (int k=_bbox.min.Z(); k<_bbox.max.Z(); k+=_cell_size.Z())
|
|
{
|
|
k_idx = k-_bbox.min.Z();
|
|
index = i_idx+k_idx*_resolution.X();
|
|
_v_ns[ index ] = _volume->V(i, j, k);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Begin()
|
|
{
|
|
_current_slice = _bbox.min.Y();
|
|
|
|
memset(_x_cs, -1, _slice_dimension*sizeof(VertexIndex));
|
|
memset(_y_cs, -1, _slice_dimension*sizeof(VertexIndex));
|
|
memset(_z_cs, -1, _slice_dimension*sizeof(VertexIndex));
|
|
memset(_x_ns, -1, _slice_dimension*sizeof(VertexIndex));
|
|
memset(_z_ns, -1, _slice_dimension*sizeof(VertexIndex));
|
|
|
|
int index;
|
|
int j = _current_slice;
|
|
int i_idx, k_idx;
|
|
for (int i=_bbox.min.X(); i<_bbox.max.X(); i+=_cell_size.X())
|
|
{
|
|
i_idx = i-_bbox.min.X();
|
|
for (int k=_bbox.min.Z(); k<_bbox.max.Z(); k+=_cell_size.Z())
|
|
{
|
|
k_idx = k-_bbox.min.Z();
|
|
index = i_idx+k_idx*_resolution.X();
|
|
_v_cs[index] = _volume->V(i, j, k);
|
|
_v_ns[index] = _volume->V(i, j+_cell_size.Y(), k);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
#endif // __VCGTEST_WALKER
|