Strongly refactored in order to guarantee better independence between the resampled mesh an the original one
This commit is contained in:
parent
3784295ac6
commit
03c2648af1
|
@ -40,37 +40,40 @@ namespace tri {
|
|||
/*@{*/
|
||||
/*@{*/
|
||||
/** Class Resampler.
|
||||
This is class reasmpling a mesh using marching cubes methods
|
||||
@param OLD_MESH_TYPE (Template Parameter) Specifies the type of mesh to be resampled
|
||||
@param NEW_MESH_TYPE (Template Parameter) Specifies the type of output mesh.
|
||||
This is class resampling a mesh using marching cubes methods
|
||||
@param OldMeshType (Template Parameter) Specifies the type of mesh to be resampled
|
||||
@param NewMeshType (Template Parameter) Specifies the type of output mesh.
|
||||
All the computations are done in the output mesh scalar type. (e.g. if you have a double mesh and you want to resample int to a float mesh the volume is kept in float)
|
||||
*/
|
||||
|
||||
template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR = vcg::face::PointDistanceBaseFunctor<typename OLD_MESH_TYPE::ScalarType > >
|
||||
class Resampler : public BasicGrid<FLT>
|
||||
template <class OldMeshType,
|
||||
class NewMeshType,
|
||||
class DISTFUNCTOR = vcg::face::PointDistanceBaseFunctor<typename OldMeshType::ScalarType > >
|
||||
class Resampler : public BasicGrid<typename NewMeshType::ScalarType>
|
||||
{
|
||||
typedef OLD_MESH_TYPE Old_Mesh;
|
||||
typedef NEW_MESH_TYPE New_Mesh;
|
||||
typedef typename NewMeshType::ScalarType NewScalarType;
|
||||
typedef typename NewMeshType::BoxType NewBoxType;
|
||||
typedef typename NewMeshType::CoordType NewCoordType;
|
||||
typedef typename NewMeshType::VertexType* NewVertexPointer;
|
||||
typedef typename NewMeshType::VertexIterator NewVertexIterator;
|
||||
typedef typename OldMeshType::CoordType OldCoordType;
|
||||
typedef typename OldMeshType::FaceContainer OldFaceCont;
|
||||
typedef typename OldMeshType::FaceType OldFaceType;
|
||||
typedef typename OldMeshType::ScalarType OldScalarType;
|
||||
|
||||
//template <class OLD_MESH_TYPE,class NEW_MESH_TYPE>
|
||||
class Walker : BasicGrid<float>
|
||||
class Walker : BasicGrid<typename NewMeshType::ScalarType>
|
||||
{
|
||||
private:
|
||||
typedef int VertexIndex;
|
||||
typedef OLD_MESH_TYPE Old_Mesh;
|
||||
typedef NEW_MESH_TYPE New_Mesh;
|
||||
typedef typename New_Mesh::CoordType NewCoordType;
|
||||
typedef typename New_Mesh::VertexType* VertexPointer;
|
||||
typedef typename Old_Mesh::FaceContainer FaceCont;
|
||||
typedef typename vcg::GridStaticPtr<typename Old_Mesh::FaceType> GridType;
|
||||
typedef typename vcg::GridStaticPtr<OldFaceType, OldScalarType> GridType;
|
||||
|
||||
protected:
|
||||
|
||||
int SliceSize;
|
||||
int CurrentSlice;
|
||||
typedef tri::FaceTmark<Old_Mesh> MarkerFace;
|
||||
typedef tri::FaceTmark<OldMeshType> MarkerFace;
|
||||
MarkerFace markerFunctor;
|
||||
|
||||
|
||||
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
|
||||
|
@ -84,21 +87,21 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
field_value* _v_cs;
|
||||
field_value* _v_ns;
|
||||
|
||||
New_Mesh *_newM;
|
||||
Old_Mesh *_oldM;
|
||||
NewMeshType *_newM;
|
||||
OldMeshType *_oldM;
|
||||
GridType _g;
|
||||
|
||||
public:
|
||||
float max_dim; // the limit value of the search (that takes into account of the offset)
|
||||
float offset; // an offset value that is always added to the returned value. Useful for extrarting isosurface at a different threshold
|
||||
NewScalarType max_dim; // the limit value of the search (that takes into account of the offset)
|
||||
NewScalarType offset; // an offset value that is always added to the returned value. Useful for extrarting isosurface at a different threshold
|
||||
bool DiscretizeFlag; // if the extracted surface should be discretized or not.
|
||||
bool MultiSampleFlag;
|
||||
bool AbsDistFlag; // if true the Distance Field computed is no more a signed one.
|
||||
Walker(const Box3f &_bbox, Point3i _siz )
|
||||
Walker(const Box3<NewScalarType> &_bbox, Point3i _siz )
|
||||
{
|
||||
this->bbox= _bbox;
|
||||
this->siz=_siz;
|
||||
ComputeDimAndVoxel();
|
||||
this->ComputeDimAndVoxel();
|
||||
|
||||
SliceSize = (this->siz.X()+1)*(this->siz.Z()+1);
|
||||
CurrentSlice = 0;
|
||||
|
@ -122,13 +125,13 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
{}
|
||||
|
||||
|
||||
float V(const Point3i &p)
|
||||
NewScalarType V(const Point3i &p)
|
||||
{
|
||||
return V(p.V(0),p.V(1),p.V(2));
|
||||
}
|
||||
|
||||
|
||||
std::pair<bool,float> VV(int x,int y,int z)
|
||||
std::pair<bool,NewScalarType> VV(int x,int y,int z)
|
||||
{
|
||||
assert ((y==CurrentSlice)||(y==(CurrentSlice+1)));
|
||||
|
||||
|
@ -142,53 +145,48 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
else return _v_ns[index];
|
||||
}
|
||||
|
||||
float V(int x,int y,int z)
|
||||
NewScalarType V(int x,int y,int z)
|
||||
{
|
||||
if(DiscretizeFlag) return VV(x,y,z).second+offset<0?-1:1;
|
||||
return VV(x,y,z).second+offset;
|
||||
}
|
||||
///return true if the distance form the mesh is less than maxdim and return distance
|
||||
field_value DistanceFromMesh(Point3f &pp,Old_Mesh */*mesh*/)
|
||||
field_value DistanceFromMesh(OldCoordType &pp)
|
||||
{
|
||||
float dist;
|
||||
typename Old_Mesh::FaceType *f=NULL;
|
||||
const float max_dist = max_dim;
|
||||
vcg::Point3f testPt;
|
||||
OldScalarType dist;
|
||||
const NewScalarType max_dist = max_dim;
|
||||
OldCoordType testPt;
|
||||
this->IPfToPf(pp,testPt);
|
||||
|
||||
vcg::Point3f closestNormV,closestNormF;
|
||||
vcg::Point3f closestPt;
|
||||
vcg::Point3f pip(-1,-1,-1);
|
||||
|
||||
// Note that PointDistanceBaseFunctor does not require the edge and plane precomptued.
|
||||
// while the PointDistanceFunctor requires them.
|
||||
|
||||
OldCoordType closestPt;
|
||||
DISTFUNCTOR PDistFunct;
|
||||
f = _g.GetClosest(PDistFunct,markerFunctor,testPt,max_dist,dist,closestPt);
|
||||
OldFaceType *f = _g.GetClosest(PDistFunct,markerFunctor,testPt,max_dist,dist,closestPt);
|
||||
if (f==NULL) return field_value(false,0);
|
||||
if(AbsDistFlag) return field_value(true,dist);
|
||||
assert(!f->IsD());
|
||||
bool retIP;
|
||||
|
||||
// To compute the interpolated normal we use the more robust function that require to know what is the most orhogonal direction of the face.
|
||||
OldCoordType pip(-1,-1,-1);
|
||||
retIP=InterpolationParameters(*f,(*f).cN(),closestPt, pip);
|
||||
assert(retIP); // this should happen only if the starting mesh has degenerate faces.
|
||||
|
||||
const float InterpolationEpsilon = 0.00001f;
|
||||
const NewScalarType InterpolationEpsilon = 0.00001f;
|
||||
int zeroCnt=0;
|
||||
if(pip[0]<InterpolationEpsilon) ++zeroCnt;
|
||||
if(pip[1]<InterpolationEpsilon) ++zeroCnt;
|
||||
if(pip[2]<InterpolationEpsilon) ++zeroCnt;
|
||||
assert(zeroCnt<3);
|
||||
|
||||
Point3f dir=(testPt-closestPt).Normalize();
|
||||
OldCoordType dir=(testPt-closestPt).Normalize();
|
||||
|
||||
// Note that the two signs could be discordant.
|
||||
// Always choose the best one according to where the nearest point falls.
|
||||
float signBest;
|
||||
NewScalarType signBest;
|
||||
|
||||
// Compute test if the point see the surface normal from inside or outside
|
||||
// Surface normal for improved robustness is computed both by face and interpolated from vertices.
|
||||
OldCoordType closestNormV, closestNormF;
|
||||
if(zeroCnt>0) // we Not are in the middle of the face so the face normal is NOT reliable.
|
||||
{
|
||||
closestNormV = (f->V(0)->cN())*pip[0] + (f->V(1)->cN())*pip[1] + (f->V(2)->cN())*pip[2] ;
|
||||
|
@ -205,23 +203,23 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
return field_value(true,dist);
|
||||
}
|
||||
|
||||
field_value MultiDistanceFromMesh(Point3f &pp, Old_Mesh */*mesh*/)
|
||||
field_value MultiDistanceFromMesh(OldCoordType &pp)
|
||||
{
|
||||
float distSum=0;
|
||||
int positiveCnt=0; // positive results counter
|
||||
const int MultiSample=7;
|
||||
const Point3f delta[7]={Point3f(0,0,0),
|
||||
Point3f( 0.2, -0.01, -0.02),
|
||||
Point3f(-0.2, 0.01, 0.02),
|
||||
Point3f( 0.01, 0.2, 0.01),
|
||||
Point3f( 0.03, -0.2, -0.03),
|
||||
Point3f(-0.02, -0.03, 0.2 ),
|
||||
Point3f(-0.01, 0.01, -0.2 )};
|
||||
const OldCoordType delta[7]={OldCoordType(0,0,0),
|
||||
OldCoordType( 0.2, -0.01, -0.02),
|
||||
OldCoordType(-0.2, 0.01, 0.02),
|
||||
OldCoordType( 0.01, 0.2, 0.01),
|
||||
OldCoordType( 0.03, -0.2, -0.03),
|
||||
OldCoordType(-0.02, -0.03, 0.2 ),
|
||||
OldCoordType(-0.01, 0.01, -0.2 )};
|
||||
|
||||
for(int qq=0;qq<MultiSample;++qq)
|
||||
{
|
||||
Point3f pp2=pp+delta[qq];
|
||||
field_value ff= DistanceFromMesh(pp2,_oldM);
|
||||
OldCoordType pp2=pp+delta[qq];
|
||||
field_value ff= DistanceFromMesh(pp2);
|
||||
if(ff.first==false) return field_value(false,0);
|
||||
distSum += fabs(ff.second);
|
||||
if(ff.second>0) positiveCnt ++;
|
||||
|
@ -239,9 +237,9 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
for (int k=0; k<=this->siz.Z(); k++)
|
||||
{
|
||||
int index=GetSliceIndex(i,k);
|
||||
Point3f pp(i,slice,k);
|
||||
if(this->MultiSampleFlag) slice_values[index] = MultiDistanceFromMesh(pp,_oldM);
|
||||
else slice_values[index] = DistanceFromMesh(pp,_oldM);
|
||||
OldCoordType pp(i,slice,k);
|
||||
if(this->MultiSampleFlag) slice_values[index] = MultiDistanceFromMesh(pp);
|
||||
else slice_values[index] = DistanceFromMesh(pp);
|
||||
}
|
||||
}
|
||||
//ComputeConsensus(slice,slice_values);
|
||||
|
@ -251,7 +249,7 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
For some reasons it can happens that the sign of the computed distance could not correct.
|
||||
this function tries to correct these issues by flipping the isolated voxels with discordant sign
|
||||
*/
|
||||
void ComputeConsensus(int slice, field_value *slice_values)
|
||||
void ComputeConsensus(int /*slice*/, field_value *slice_values)
|
||||
{
|
||||
float max_dist = min(min(this->voxel[0],this->voxel[1]),this->voxel[2]);
|
||||
int flippedCnt=0;
|
||||
|
@ -321,14 +319,14 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
|
||||
|
||||
template<class EXTRACTOR_TYPE>
|
||||
void BuildMesh(Old_Mesh &old_mesh,New_Mesh &new_mesh,EXTRACTOR_TYPE &extractor,vcg::CallBackPos *cb)
|
||||
void BuildMesh(OldMeshType &old_mesh,NewMeshType &new_mesh,EXTRACTOR_TYPE &extractor,vcg::CallBackPos *cb)
|
||||
{
|
||||
_newM=&new_mesh;
|
||||
_oldM=&old_mesh;
|
||||
|
||||
// the following two steps are required to be sure that the point-face distance without precomputed data works well.
|
||||
tri::UpdateNormal<Old_Mesh>::PerFaceNormalized(old_mesh);
|
||||
tri::UpdateNormal<Old_Mesh>::PerVertexAngleWeighted(old_mesh);
|
||||
tri::UpdateNormal<OldMeshType>::PerFaceNormalized(old_mesh);
|
||||
tri::UpdateNormal<OldMeshType>::PerVertexAngleWeighted(old_mesh);
|
||||
int _size=(int)old_mesh.fn*100;
|
||||
|
||||
_g.Set(_oldM->face.begin(),_oldM->face.end(),_size);
|
||||
|
@ -345,11 +343,10 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
NextSlice();
|
||||
}
|
||||
extractor.Finalize();
|
||||
typename New_Mesh::VertexIterator vi;
|
||||
for(vi=new_mesh.vert.begin();vi!=new_mesh.vert.end();++vi)
|
||||
for(NewVertexIterator vi=new_mesh.vert.begin();vi!=new_mesh.vert.end();++vi)
|
||||
if(!(*vi).IsD())
|
||||
{
|
||||
IPfToPf((*vi).cP(),(*vi).P());
|
||||
this->IPfToPf((*vi).cP(),(*vi).P());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,7 +395,7 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
|
||||
|
||||
|
||||
bool Exist(const vcg::Point3i &p1, const vcg::Point3i &p2, VertexPointer &v)
|
||||
bool Exist(const vcg::Point3i &p1, const vcg::Point3i &p2, NewVertexPointer &v)
|
||||
{
|
||||
int i = p1.X();// - _bbox.min.X())/_cell_size.X();
|
||||
int z = p1.Z();// - _bbox.min.Z())/_cell_size.Z();
|
||||
|
@ -482,16 +479,16 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
///interpolate
|
||||
NewCoordType Interpolate(const vcg::Point3i &p1, const vcg::Point3i &p2,int dir)
|
||||
{
|
||||
float f1 = (float)V(p1);
|
||||
float f2 = (float)V(p2);
|
||||
float u = (float) f1/(f1-f2);
|
||||
NewCoordType ret=vcg::Point3f((float)p1.V(0),(float)p1.V(1),(float)p1.V(2));
|
||||
ret.V(dir) = (float) p1.V(dir)*(1.f-u) + u*(float)p2.V(dir);
|
||||
NewScalarType f1 = V(p1);
|
||||
NewScalarType f2 = V(p2);
|
||||
NewScalarType u = f1/(f1-f2);
|
||||
NewCoordType ret(p1.V(0),p1.V(1),p1.V(2));
|
||||
ret.V(dir) = p1.V(dir)*(1.f-u) + u*p2.V(dir);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
///if there is a vertex in z axis of a cell return the vertex or create it
|
||||
void GetXIntercept(const vcg::Point3i &p1, const vcg::Point3i &p2, VertexPointer &v)
|
||||
void GetXIntercept(const vcg::Point3i &p1, const vcg::Point3i &p2, NewVertexPointer &v)
|
||||
{
|
||||
assert(p1.X()+1 == p2.X());
|
||||
assert(p1.Y() == p2.Y());
|
||||
|
@ -507,7 +504,7 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
{
|
||||
_x_cs[index] = (VertexIndex) _newM->vert.size();
|
||||
pos = _x_cs[index];
|
||||
Allocator<New_Mesh>::AddVertices( *_newM, 1 );
|
||||
Allocator<NewMeshType>::AddVertices( *_newM, 1 );
|
||||
v = &_newM->vert[pos];
|
||||
v->P()=Interpolate(p1,p2,0);
|
||||
return;
|
||||
|
@ -519,7 +516,7 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
{
|
||||
_x_ns[index] = (VertexIndex) _newM->vert.size();
|
||||
pos = _x_ns[index];
|
||||
Allocator<New_Mesh>::AddVertices( *_newM, 1 );
|
||||
Allocator<NewMeshType>::AddVertices( *_newM, 1 );
|
||||
v = &_newM->vert[pos];
|
||||
v->P()=Interpolate(p1,p2,0);
|
||||
return;
|
||||
|
@ -530,7 +527,7 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
}
|
||||
|
||||
///if there is a vertex in y axis of a cell return the vertex or create it
|
||||
void GetYIntercept(const vcg::Point3i &p1, const vcg::Point3i &p2, VertexPointer &v)
|
||||
void GetYIntercept(const vcg::Point3i &p1, const vcg::Point3i &p2, NewVertexPointer &v)
|
||||
{
|
||||
assert(p1.X() == p2.X());
|
||||
assert(p1.Y()+1 == p2.Y());
|
||||
|
@ -544,7 +541,7 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
{
|
||||
_y_cs[index] = (VertexIndex) _newM->vert.size();
|
||||
pos = _y_cs[index];
|
||||
Allocator<New_Mesh>::AddVertices( *_newM, 1);
|
||||
Allocator<NewMeshType>::AddVertices( *_newM, 1);
|
||||
v = &_newM->vert[ pos ];
|
||||
v->P()=Interpolate(p1,p2,1);
|
||||
}
|
||||
|
@ -553,7 +550,7 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
}
|
||||
|
||||
///if there is a vertex in z axis of a cell return the vertex or create it
|
||||
void GetZIntercept(const vcg::Point3i &p1, const vcg::Point3i &p2, VertexPointer &v)
|
||||
void GetZIntercept(const vcg::Point3i &p1, const vcg::Point3i &p2, NewVertexPointer &v)
|
||||
{
|
||||
assert(p1.X() == p2.X());
|
||||
assert(p1.Y() == p2.Y());
|
||||
|
@ -570,7 +567,7 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
{
|
||||
_z_cs[index] = (VertexIndex) _newM->vert.size();
|
||||
pos = _z_cs[index];
|
||||
Allocator<New_Mesh>::AddVertices( *_newM, 1 );
|
||||
Allocator<NewMeshType>::AddVertices( *_newM, 1 );
|
||||
v = &_newM->vert[pos];
|
||||
v->P()=Interpolate(p1,p2,2);
|
||||
return;
|
||||
|
@ -582,7 +579,7 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
{
|
||||
_z_ns[index] = (VertexIndex) _newM->vert.size();
|
||||
pos = _z_ns[index];
|
||||
Allocator<New_Mesh>::AddVertices( *_newM, 1 );
|
||||
Allocator<NewMeshType>::AddVertices( *_newM, 1 );
|
||||
v = &_newM->vert[pos];
|
||||
v->P()=Interpolate(p1,p2,2);
|
||||
return;
|
||||
|
@ -596,15 +593,15 @@ template <class OLD_MESH_TYPE,class NEW_MESH_TYPE, class FLT, class DISTFUNCTOR
|
|||
|
||||
public:
|
||||
|
||||
typedef Walker /*< Old_Mesh,New_Mesh>*/ MyWalker;
|
||||
typedef Walker /*< Old_Mesh,New_Mesh>*/ MyWalker;
|
||||
|
||||
typedef vcg::tri::MarchingCubes<New_Mesh, MyWalker> MyMarchingCubes;
|
||||
typedef vcg::tri::MarchingCubes<NewMeshType, MyWalker> MyMarchingCubes;
|
||||
|
||||
///resample the mesh using marching cube algorithm ,the accuracy is the dimension of one cell the parameter
|
||||
static void Resample(Old_Mesh &old_mesh,New_Mesh &new_mesh, Box3f volumeBox, vcg::Point3<int> accuracy,float max_dist, float thr=0, bool DiscretizeFlag=false, bool MultiSampleFlag=false, bool AbsDistFlag=false, vcg::CallBackPos *cb=0 )
|
||||
{
|
||||
///resample the mesh using marching cube algorithm ,the accuracy is the dimension of one cell the parameter
|
||||
static void Resample(OldMeshType &old_mesh, NewMeshType &new_mesh, NewBoxType volumeBox, vcg::Point3<int> accuracy,float max_dist, float thr=0, bool DiscretizeFlag=false, bool MultiSampleFlag=false, bool AbsDistFlag=false, vcg::CallBackPos *cb=0 )
|
||||
{
|
||||
///be sure that the bounding box is updated
|
||||
vcg::tri::UpdateBounding<Old_Mesh>::Box(old_mesh);
|
||||
vcg::tri::UpdateBounding<OldMeshType>::Box(old_mesh);
|
||||
|
||||
MyWalker walker(volumeBox,accuracy);
|
||||
|
||||
|
@ -615,11 +612,11 @@ static void Resample(Old_Mesh &old_mesh,New_Mesh &new_mesh, Box3f volumeBox, vc
|
|||
walker.AbsDistFlag = AbsDistFlag;
|
||||
MyMarchingCubes mc(new_mesh, walker);
|
||||
walker.BuildMesh(old_mesh,new_mesh,mc,cb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};//end class resampler
|
||||
|
||||
};//end namespace tri
|
||||
};//end namespace vcg
|
||||
}//end namespace tri
|
||||
}//end namespace vcg
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue