From 2556d779ab69f7a2283c4fd2ddabcc2b45e41d39 Mon Sep 17 00:00:00 2001 From: Paolo Cignoni cignoni Date: Tue, 14 Sep 2010 17:04:29 +0000 Subject: [PATCH] 1) added iterator based traversal to 3D-DDR 2) modified balloon to use iterators 3) added "support" weight interpolator --- src/meshlabplugins/edit_vase/balloon.cpp | 67 ++++++++++++---- src/meshlabplugins/edit_vase/balloon.h | 3 +- .../edit_vase/fieldinterpolator.cpp | 2 +- src/meshlabplugins/edit_vase/gridaccell.cpp | 80 +++++++++++++++++++ src/meshlabplugins/edit_vase/gridaccell.h | 52 +++++++++++- 5 files changed, 184 insertions(+), 20 deletions(-) diff --git a/src/meshlabplugins/edit_vase/balloon.cpp b/src/meshlabplugins/edit_vase/balloon.cpp index 35ab3e308..b6c7b296e 100644 --- a/src/meshlabplugins/edit_vase/balloon.cpp +++ b/src/meshlabplugins/edit_vase/balloon.cpp @@ -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[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; iray; + for(gridAccell.iter.first(fcenter); !gridAccell.iter.isDone(); gridAccell.iter.next()){ + Ray3f& ray = gridAccell.iter.currentItem().ray; + if( vcg::IntersectionRayTriangle(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 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 line(pray.ray.Origin(), pray.ray.Direction()); + + // for(unsigned int i=0; i 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)t) ){ - prays[i]->f=&f; - prays[i]->t=t; + if( pray.f==NULL || fabs(t)=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 H; tri::Stat::ComputePerVertexQualityHistogram(surf,H); tri::UpdateColor::VertexQualityRamp(surf,H.Percentile(0.0f),H.Percentile(1.0f)); diff --git a/src/meshlabplugins/edit_vase/balloon.h b/src/meshlabplugins/edit_vase/balloon.h index 493cfcb59..bc042697e 100644 --- a/src/meshlabplugins/edit_vase/balloon.h +++ b/src/meshlabplugins/edit_vase/balloon.h @@ -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(); diff --git a/src/meshlabplugins/edit_vase/fieldinterpolator.cpp b/src/meshlabplugins/edit_vase/fieldinterpolator.cpp index d58ac0fa6..5799961c5 100644 --- a/src/meshlabplugins/edit_vase/fieldinterpolator.cpp +++ b/src/meshlabplugins/edit_vase/fieldinterpolator.cpp @@ -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; diff --git a/src/meshlabplugins/edit_vase/gridaccell.cpp b/src/meshlabplugins/edit_vase/gridaccell.cpp index e1b737995..4be264315 100644 --- a/src/meshlabplugins/edit_vase/gridaccell.cpp +++ b/src/meshlabplugins/edit_vase/gridaccell.cpp @@ -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] ); +} diff --git a/src/meshlabplugins/edit_vase/gridaccell.h b/src/meshlabplugins/edit_vase/gridaccell.h index 050a047da..fb6a7731c 100644 --- a/src/meshlabplugins/edit_vase/gridaccell.h +++ b/src/meshlabplugins/edit_vase/gridaccell.h @@ -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=0 && i0 && 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