mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-18 18:44:39 +00:00
1) added iterator based traversal to 3D-DDR
2) modified balloon to use iterators 3) added "support" weight interpolator
This commit is contained in:
parent
6ace2ea140
commit
2556d779ab
@ -53,21 +53,34 @@ void Balloon::init( int gridsize, int gridpad ){
|
||||
vol.band.reserve(5*surf.fn);
|
||||
vol.updateSurfaceCorrespondence( surf, gridAccell, 2*vol.getDelta() );
|
||||
}
|
||||
|
||||
bool Balloon::initializeField(){
|
||||
//--- Setup the interpolation system
|
||||
// if we fail, signal the failure to the caller
|
||||
// Lower levels of omega might cause overshoothing problems
|
||||
// float OMEGA = 1e3; // 1e8
|
||||
float OMEGA = 1e8; // 1e8
|
||||
|
||||
LAPLACIAN type = COTANGENT; // COMBINATORIAL
|
||||
bool op_succeed = finterp.Init( &surf, 1, type );
|
||||
bool op_succeed = finterp.Init( &surf, 1, type );
|
||||
if( !op_succeed ){
|
||||
finterp.ColorizeIllConditioned( type );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
float OMEGA_VERTEX = 1e-1;
|
||||
float OMEGA_DATA = 1e-1;
|
||||
winterp.Init( &surf, 1, type );
|
||||
if( !op_succeed ){
|
||||
winterp.ColorizeIllConditioned( type );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Shared data
|
||||
enum INITMODE {BIFACEINTERSECTIONS, FACEINTERSECTIONS, BOXINTERSECTIONS} mode;
|
||||
// mode = BIFACEINTERSECTIONS;
|
||||
mode = BIFACEINTERSECTIONS;
|
||||
const float ONETHIRD = 1.0f/3.0f;
|
||||
float t,u,v; // Ray-Triangle intersection parameters
|
||||
@ -87,7 +100,9 @@ bool Balloon::initializeField(){
|
||||
f.C() = ( rays.size()>0 ) ? Color4b(255,0,0,255) : Color4b(255,255,255,255);
|
||||
}
|
||||
qDebug() << "WARNING: test-mode only, per vertex field not updated!!";
|
||||
}
|
||||
}
|
||||
// Each intersecting ray gives a contribution on the face to each of the
|
||||
// face vertices according to the barycentric weights
|
||||
else if( mode == FACEINTERSECTIONS ){
|
||||
this->rm ^= SURF_VCOLOR;
|
||||
this->rm |= SURF_FCOLOR;
|
||||
@ -102,12 +117,13 @@ bool Balloon::initializeField(){
|
||||
f.Q() = 0; // initialize
|
||||
Point3f fcenter = f.P(0) + f.P(1) + f.P(2);
|
||||
fcenter = myscale( fcenter, ONETHIRD );
|
||||
gridAccell.pos2off( fcenter, off );
|
||||
PointerVector& prays = gridAccell.Val(off[0], off[1], off[2]);
|
||||
// Each intersecting ray gives a contribution on the face to each of the
|
||||
// face vertices according to the barycentric weights
|
||||
for(unsigned int i=0; i<prays.size(); i++)
|
||||
if( vcg::IntersectionRayTriangle<float>(prays[i]->ray, f.P(0), f.P(1), f.P(2), t, u, v) ){
|
||||
// NEW/OLD ITERATOR
|
||||
// gridAccell.pos2off( fcenter, off );
|
||||
// PointerVector& prays = gridAccell.Val(off[0], off[1], off[2]);
|
||||
// for(unsigned int i=0; i<prays.size(); i++){ Ray3f& ray = prays[i]->ray;
|
||||
for(gridAccell.iter.first(fcenter); !gridAccell.iter.isDone(); gridAccell.iter.next()){
|
||||
Ray3f& ray = gridAccell.iter.currentItem().ray;
|
||||
if( vcg::IntersectionRayTriangle<float>(ray, f.P(0), f.P(1), f.P(2), t, u, v) ){
|
||||
// Color the faces, if more than one, take average
|
||||
tot_w[ tri::Index(surf,f) ]++;
|
||||
f.Q() += t; // normalize with tot_w after
|
||||
@ -117,6 +133,7 @@ bool Balloon::initializeField(){
|
||||
finterp.AddConstraint( tri::Index(surf,f.V(1)), OMEGA*(u), t );
|
||||
finterp.AddConstraint( tri::Index(surf,f.V(2)), OMEGA*(v), t );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--- Normalize in case there is more than 1 ray per-face
|
||||
@ -162,8 +179,13 @@ bool Balloon::initializeField(){
|
||||
// We check each of the possibly intersecting rays and we associate this face
|
||||
// with him if and only if this face is the closest to it. Note that we study
|
||||
// the values of t,u,v directly as a t<0 is accepted as intersecting.
|
||||
for(unsigned int i=0; i<prays.size(); i++){
|
||||
Line3<float> line(prays[i]->ray.Origin(), prays[i]->ray.Direction());
|
||||
for(gridAccell.iter.first(f); !gridAccell.iter.isDone(); gridAccell.iter.next()){
|
||||
// for(gridAccell.iter.first(fcenter); !gridAccell.iter.isDone(); gridAccell.iter.next()){
|
||||
PokingRay& pray = gridAccell.iter.currentItem();
|
||||
Line3<float> line(pray.ray.Origin(), pray.ray.Direction());
|
||||
|
||||
// for(unsigned int i=0; i<prays.size(); i++){
|
||||
// Line3<float> line(prays[i]->ray.Origin(), prays[i]->ray.Direction());
|
||||
|
||||
// If the ray falls within the domain of the face
|
||||
if( IntersectionLineTriangle(line, f.P(0), f.P(1), f.P(2), t, u, v) ){
|
||||
@ -179,14 +201,18 @@ bool Balloon::initializeField(){
|
||||
|
||||
// If no face was associated with this ray or this face is closer
|
||||
// than the one that I stored previously
|
||||
if( prays[i]->f==NULL || fabs(t)<fabs(prays[i]->t) ){
|
||||
prays[i]->f=&f;
|
||||
prays[i]->t=t;
|
||||
if( pray.f==NULL || fabs(t)<fabs(pray.t) ){
|
||||
pray.f=&f;
|
||||
pray.t=t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--- Add constraints on vertexes of balloon
|
||||
for(CMeshO::VertexIterator vi=surf.vert.begin();vi!=surf.vert.end();vi++)
|
||||
winterp.AddConstraint( tri::Index(surf,*vi), OMEGA_VERTEX, 0 );
|
||||
|
||||
// Now we scan through the rays, we visit the "best" corresponding face and we
|
||||
// set a constraint on this face. Also we modify the color of the face so that
|
||||
// an approximation can be visualized
|
||||
@ -217,6 +243,12 @@ bool Balloon::initializeField(){
|
||||
finterp.AddConstraint( tri::Index(surf,f.V(0)), OMEGA*(1-u-v), t );
|
||||
finterp.AddConstraint( tri::Index(surf,f.V(1)), OMEGA*(u), t );
|
||||
finterp.AddConstraint( tri::Index(surf,f.V(2)), OMEGA*(v), t );
|
||||
|
||||
//--- And for the second interpolator
|
||||
winterp.AddConstraint( tri::Index(surf,f.V(0)), OMEGA_DATA*(1-u-v), 1 );
|
||||
winterp.AddConstraint( tri::Index(surf,f.V(1)), OMEGA_DATA*(u), 1 );
|
||||
winterp.AddConstraint( tri::Index(surf,f.V(2)), OMEGA_DATA*(v), 1 );
|
||||
|
||||
assert( u>=0 && u<=1 && v>=0 && v<=1 );
|
||||
}
|
||||
|
||||
@ -236,11 +268,14 @@ void Balloon::interpolateField(){
|
||||
surf.vert.QualityEnabled = true;
|
||||
|
||||
//--- Interpolate the field
|
||||
finterp.SolveInQuality();
|
||||
|
||||
// finterp.SolveInQuality();
|
||||
|
||||
//--- Interpolate the field
|
||||
winterp.SolveInQuality();
|
||||
|
||||
//--- Transfer vertex quality to surface
|
||||
rm &= ~SURF_FCOLOR; // disable face colors
|
||||
rm |= SURF_VCOLOR; // enable vertex colors
|
||||
rm |= SURF_VCOLOR; // enable vertex colors
|
||||
Histogram<float> H;
|
||||
tri::Stat<CMeshO>::ComputePerVertexQualityHistogram(surf,H);
|
||||
tri::UpdateColor<CMeshO>::VertexQualityRamp(surf,H.Percentile(0.0f),H.Percentile(1.0f));
|
||||
|
||||
@ -38,6 +38,8 @@ public:
|
||||
GridAccell gridAccell;
|
||||
/// Scalar field interpolator (one constraint per poking ray)
|
||||
FieldInterpolator finterp;
|
||||
/// How close am I to the data? (1: close 0: far)
|
||||
FieldInterpolator winterp;
|
||||
/// Smoothing interpolator (one constraint per vertex)
|
||||
FieldInterpolator sinterp;
|
||||
|
||||
@ -49,7 +51,6 @@ public:
|
||||
/// Constructor: set default render mode
|
||||
Balloon( CMeshO& _cloud ) : cloud( _cloud ){}
|
||||
|
||||
|
||||
//--- Logic (if failed, return != 0)
|
||||
void init(int gridsize, int gridpad);
|
||||
bool initializeField();
|
||||
|
||||
@ -193,7 +193,7 @@ void FieldInterpolator::ColorizeIllConditioned(LAPLACIAN laptype){
|
||||
if( alpha==0 ){
|
||||
fi->V(icurr)->Q() = 1;
|
||||
float ratio = (f.P(iprev)-f.P(inext)).Norm() / va.Norm();
|
||||
qDebug("ratio between edges: %.4f", ratio);
|
||||
// qDebug("ratio between edges: %.4f", ratio);
|
||||
|
||||
}
|
||||
// if( alpha==0 ) fi->V(iprev)->Q() = 1;
|
||||
|
||||
@ -26,6 +26,8 @@ void GridAccell::init( MyVolume& vol, CMeshO& pcloud ){
|
||||
// if( i!=12 ) continue;
|
||||
trace_ray( rays[i] );
|
||||
}
|
||||
// Initializes the iterator
|
||||
iter.init(this);
|
||||
}
|
||||
void GridAccell::trace_ray(PokingRay& pray, float off){
|
||||
// We want to go behind the pixel, you better give me a default of 0,
|
||||
@ -119,3 +121,81 @@ void GridAccell::clearCorrespondences(){
|
||||
rays[i].t = +FLT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
//
|
||||
// ITERATOR / QUERY
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
void GridAccellIterator::init(GridAccell* parent){
|
||||
this->parent = parent;
|
||||
this->v = &( parent->Val(0,0,0) );
|
||||
}
|
||||
void GridAccellIterator::first(Point3f& p){
|
||||
//--- Convert the bounding box in grid space
|
||||
parent->pos2off( p, box.max );
|
||||
box.min = box.max;
|
||||
|
||||
//--- Initialize starting point
|
||||
curr = box.min;
|
||||
v = &( parent->Val(curr) );
|
||||
offset = 0;
|
||||
}
|
||||
void GridAccellIterator::first(CFaceO& f){
|
||||
//--- Compute bbox of face
|
||||
Box3f f_bbox;
|
||||
f_bbox.Add(f.P(0));
|
||||
f_bbox.Add(f.P(1));
|
||||
f_bbox.Add(f.P(2));
|
||||
|
||||
//--- Convert the bounding box in grid space
|
||||
parent->pos2off( f_bbox.max, box.max );
|
||||
parent->pos2off( f_bbox.min, box.min );
|
||||
|
||||
//--- Initialize starting point
|
||||
curr = box.min;
|
||||
v = &( parent->Val(curr) );
|
||||
offset = -1;
|
||||
|
||||
#ifdef DEBUG_GRIDACCELL_ITERATOR
|
||||
qDebug() << "new query initiated on " << toString(box.min);
|
||||
#endif
|
||||
|
||||
//--- Visit first valid
|
||||
this->next();
|
||||
}
|
||||
void GridAccellIterator::next(){
|
||||
#ifdef DEBUG_GRIDACCELL_ITERATOR
|
||||
qDebug() << "next element required";
|
||||
#endif
|
||||
// Until I find a non-empty list continue explore
|
||||
for(; curr.X() <= box.max.X(); curr.X()++ ){
|
||||
for(; curr.Y() <= box.max.Y(); curr.Y()++ ){
|
||||
for(; curr.Z() <= box.max.Z(); curr.Z()++ ){
|
||||
v = &( parent->Val(curr) );
|
||||
if( v->size() != 0 && ++offset < v->size() ){
|
||||
#ifdef DEBUG_GRIDACCELL_ITERATOR
|
||||
qDebug() << "Accepted next [curr: " << toString(curr) << " offset: " << offset << "]";
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_GRIDACCELL_ITERATOR
|
||||
qDebug() << "nothing has been found";
|
||||
#endif
|
||||
}
|
||||
bool GridAccellIterator::isDone(){
|
||||
bool condition = curr.X() >= box.max.X() && curr.Y() >= box.max.Y() && curr.Z() >= box.max.Z() && offset >= v->size();
|
||||
#ifdef DEBUG_GRIDACCELL_ITERATOR
|
||||
qDebug("isDone: (%s) (%d/%d %d/%d %d/%d => %d/%d)", condition?"y":"n", curr.X(),box.max.X(), curr.Y(),box.max.Y(), curr.Z(),box.max.Z(), offset+1, v->size() );
|
||||
#endif
|
||||
return condition;
|
||||
}
|
||||
PokingRay& GridAccellIterator::currentItem(){
|
||||
#ifdef DEBUG_GRIDACCELL_ITERATOR
|
||||
qDebug("extracted element");
|
||||
#endif
|
||||
return *( (*v)[offset] );
|
||||
}
|
||||
|
||||
@ -7,8 +7,10 @@
|
||||
|
||||
namespace vcg{
|
||||
|
||||
// Forward declaration
|
||||
// Forward declarations
|
||||
class MyVolume;
|
||||
class GridAccellIterator;
|
||||
class GridAccell;
|
||||
|
||||
/**
|
||||
* Each ray is a triple of elements, the startpoint/direction
|
||||
@ -36,6 +38,35 @@ public:
|
||||
typedef PokingRay* PTRTYPE;
|
||||
typedef std::vector< PTRTYPE > PointerVector;
|
||||
|
||||
/// Iterator class that queries the rays crossing a certain region
|
||||
class GridAccellIterator{
|
||||
private:
|
||||
// Reference to class over which we are iterating
|
||||
GridAccell* parent;
|
||||
// the bounds of space we are currently checking
|
||||
Box3i box;
|
||||
// the index of the element we are currently visiting
|
||||
Point3i curr;
|
||||
// the content of the element we are currently visiting
|
||||
PointerVector* v;
|
||||
// the current internal position (grid offset)
|
||||
int offset;
|
||||
public:
|
||||
GridAccellIterator(){
|
||||
parent = NULL;
|
||||
v = NULL;
|
||||
offset = 0;
|
||||
}
|
||||
void init(GridAccell* parent);
|
||||
/// Iterates over rays which intersects the box which contains the sample
|
||||
void first(Point3f& p);
|
||||
/// Iterates over rays which intersects the boxes which englobe the bounding box of the face
|
||||
void first(CFaceO& f);
|
||||
void next();
|
||||
bool isDone();
|
||||
PokingRay& currentItem();
|
||||
};
|
||||
|
||||
/**
|
||||
* Each volume cell contains a *set* of pointers which
|
||||
* might intersect the geometry defined within the same cell
|
||||
@ -57,6 +88,9 @@ private:
|
||||
float delta;
|
||||
|
||||
public:
|
||||
// Data access (to be initialized)
|
||||
GridAccellIterator iter;
|
||||
|
||||
// Coordinate change
|
||||
/// Converts a general position to a voxel index
|
||||
void pos2off( const Point3f& pos, Point3i& off ){
|
||||
@ -64,6 +98,7 @@ public:
|
||||
off[1] = pos2off( pos[1], 1 );
|
||||
off[2] = pos2off( pos[2], 2 );
|
||||
}
|
||||
|
||||
/// Converts a general position to a voxel index
|
||||
int pos2off( float p, int dim ){
|
||||
int v = round( (p-bbox.min[dim])/delta + padsize-.5 );
|
||||
@ -71,39 +106,53 @@ public:
|
||||
assert(v>=0 && v<size(dim));
|
||||
return v;
|
||||
}
|
||||
|
||||
/// Converts a volumetric offset in a 3D space coordinate
|
||||
void off2pos( int i, int j, int k, Point3f& pos ){
|
||||
pos[0] = off2pos( i, 0 );
|
||||
pos[1] = off2pos( j, 1 );
|
||||
pos[2] = off2pos( k, 2 );
|
||||
}
|
||||
|
||||
/// Converts a volumetric offset in a 3D space coordinate
|
||||
void off2pos( Point3i off, Point3f& pos ){
|
||||
pos[0] = off2pos( off[0], 0 );
|
||||
pos[1] = off2pos( off[1], 1 );
|
||||
pos[2] = off2pos( off[2], 2 );
|
||||
}
|
||||
|
||||
/// Converts an offset on grid in object space coordinate
|
||||
float off2pos( int i, int dim ){
|
||||
assert(i>=0 && i<size(dim));
|
||||
return (i-padsize+.5)*delta + bbox.min[dim];
|
||||
}
|
||||
|
||||
/// Does not allocate memory, refer to Init
|
||||
GridAccell(){ sz=Point3i(0,0,0); }
|
||||
|
||||
/// Allocates memory for a grid of the given size
|
||||
void init( MyVolume& v, CMeshO& pcloud );
|
||||
|
||||
/// Accessor for memory grid representation
|
||||
inline PointerVector& Val( Point3i p ){
|
||||
return Val(p.X(), p.Y(), p.Z());
|
||||
}
|
||||
/// Accessor for memory grid representation
|
||||
inline PointerVector& Val( const int x, const int y, const int z ){
|
||||
return Vol[x+y*sz[0]+z*sz[0]*sz[1]];
|
||||
}
|
||||
|
||||
/// Has this volume been initialized?
|
||||
inline bool isInit(){
|
||||
return sz[0]>0 && sz[1]>0 && sz[2]>0;
|
||||
}
|
||||
|
||||
/// Size of the volume in specific dimension (padding included)
|
||||
inline const int size(int dim){ return sz[dim]; }
|
||||
|
||||
/// Renders the intersections
|
||||
void render();
|
||||
|
||||
/// Trace a ray in the current volume updating PointerVectors in the traversed cells
|
||||
/// Before starting the marching we pull the ray back of the quantity "off", so that
|
||||
/// we are able to test for intersections with triangles which are slightly behind
|
||||
@ -113,7 +162,6 @@ public:
|
||||
/// This function scans through the PokingRay array and reset the correspondence information
|
||||
/// and the distance information (used to compute a new correspondence)
|
||||
void clearCorrespondences();
|
||||
|
||||
};
|
||||
|
||||
} // Namespace VCG
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user