1 #ifndef VOLUME_H 2 #define VOLUME_H 3 4 #include <QDebug> 5 #include <vector> //STD vector 6 #include <QPainter> // Draw slice 7 #include <common/interfaces.h> // Lots of meshlab stuff 8 9 #include <vcg/complex/algorithms/create/mc_trivial_walker.h> // SimpleVolume 10 #include <vcg/complex/algorithms/create/marching_cubes.h> // Marching cube 11 #include "gridaccell.h" // Grid ray accellerator 12 #include "vase_utils.h" 13 14 15 namespace vcg{ 16 17 // Forward declare 18 class GridAccell; 19 20 /** 21 * This is a trivial extension of the class vcg::SimpleVoxel, it does not only 22 * hold a field value, but also a pointer to the face responsible for that field 23 * value. If a face needs to move (perpendicular to the normal, like in a balloon) 24 * then we will be able to retrieve the necessary movement of this field by visiting 25 * the corresponding face and querying the variation at that particular location. 26 */ 27 class MyVoxel{ 28 public: 29 float sfield; // signed distance from surface 30 float field; // unsigned distance from surface (used for the band updating) 31 CFaceO* face; // corresponding balloon face 32 int status; // status: {0: untouched, 1: in queue, 2: popped} 33 int index; // index of MyVoxel in current active band 34 /// Set field to zero and NULL the face pointer MyVoxel()35 MyVoxel(){ 36 sfield = 0; 37 field = 0; 38 face = 0; 39 status = 0; 40 index = 0; 41 } 42 /// Required by marching cubes V()43 float &V(){ 44 return sfield; 45 } 46 }; 47 /** 48 * An implicit volumetric class: 49 * 50 * There is a fishy relationship in between the indexing used in the volume class and the 51 * one used in the gridaccell class. I think it's related to the way in which marching cubes 52 * extracts the isosurface. While gridaccell will have the -.5/+.5 correction, the volume 53 * needs to work on integer coordinates with no post-correction. In this way the extracted 54 * isosurface is perfectly aligned with the ray-grid created by gridaccell. I would like to 55 * investigate this particular relationship but the tests show that it work... and that's 56 * all I have time for. If anything can be changed, it's within volume... gridaccell should 57 * be left alone as the 3D-DDR is highly dependent on the way in which the grid is 58 * structured. 59 * 60 */ 61 class MyVolume{ 62 private: 63 // Internal uniform grid representation 64 SimpleVolume<MyVoxel> grid; 65 // Size of the underlying grid (voxels) 66 Point3i sz; 67 // Padding of the volume 68 int padsize; 69 // Real dimension of a voxel 70 float delta; 71 // Volume represented by the grid 72 vcg::Box3f bbox; 73 // Pre allocated 2D matrixes for slicing 74 QPixmap slices_2D[3]; 75 76 public: 77 78 /// Compute volume-to-surface correspondences (stored in MyVoxel::face) in a band around the surface 79 /// up to DELTA away (in object space) inserting the volumetric indexes in the band vector. 80 /// Used by initField(CMeshO&, accell) 81 void updateSurfaceCorrespondence( CMeshO& balloon_mesh, GridAccell& gridAccell, float DELTA ); 82 83 /// Indexes of current band 84 std::vector<Point3i> band; 85 86 // Constructors / Factories 87 /// Empty, refer to Init(...) MyVolume()88 MyVolume(){ sz=Point3i(0,0,0); } 89 /// Initialize the volume 90 void init( int gridsize, int padsize, vcg::Box3f bbox ); 91 /// Retrieves a 2D (image) slice from the volume 92 QPixmap& getSlice(int dim, int slice); 93 /// Set SEDF according to continuous function 94 void initField( const vcg::Box3f& bbox ); 95 /// Set SEDF so that MC woudl give "surface" as output 96 void initField( CMeshO& surface, GridAccell& accell ); 97 /// Computes isosurface of current volume 98 void isosurface( CMeshO& balloon_mesh, float offset=0 ); 99 /// Render every cube just for illustration 100 void render(); 101 /// Check sample in range checkRange(Point3i newo)102 bool checkRange( Point3i newo ){ 103 assert( newo[0] >= 0 && newo[0] < size(0) ); 104 assert( newo[1] >= 0 && newo[1] < size(1) ); 105 assert( newo[2] >= 0 && newo[2] < size(2) ); 106 } 107 108 109 // Getters getDelta()110 float getDelta() const{ return delta; } getBbox()111 vcg::Box3f getBbox() const{ return bbox; } getSize()112 Point3i getSize() const{ return sz; } getPadding()113 int getPadding() const{ return padsize; }; 114 115 /// Has this volume been initialized? isInit()116 inline bool isInit(){ 117 return size(0)>0 && size(1)>0 && size(2)>0; 118 } 119 120 // Access methods (for assignments and similar) Voxel(const Point3i off)121 MyVoxel& Voxel(const Point3i off){ 122 return Voxel( off[0], off[1], off[2] ); 123 } Voxel(const int & x,const int & y,const int & z)124 MyVoxel& Voxel(const int &x,const int &y,const int &z){ 125 return grid.V( x, y, z ); 126 } Val(const Point3i off)127 float &Val(const Point3i off){ 128 return Val( off[0], off[1], off[2] ); 129 } Val(const int & x,const int & y,const int & z)130 float &Val(const int &x,const int &y,const int &z) { 131 return grid.Val(x,y,z); 132 } 133 134 // Info functions 135 /// Is the offset (no rounding) within the bounds of the grid (+pad) isIn(const Point3f & off)136 bool isIn( const Point3f& off ){ 137 Point3i ofi( round(off[0]), round(off[1]), round(off[2]) ); 138 return ofi[0]>=0 && ofi[0]<size(0) && 139 ofi[1]>=0 && ofi[1]<size(1) && 140 ofi[2]>=0 && ofi[2]<size(2); 141 } size()142 const Point3i& size(){ return grid.ISize(); } size(int dim)143 inline int size(int dim) { return sz[dim]; } 144 /// Converts a general position to a voxel index pos2off(const Point3f & pos,Point3i & off)145 void pos2off( const Point3f& pos, Point3i& off ){ 146 off[0] = pos2off( pos[0], 0 ); 147 off[1] = pos2off( pos[1], 1 ); 148 off[2] = pos2off( pos[2], 2 ); 149 } 150 /// Converts a general position to a voxel index pos2off(float p,int dim)151 int pos2off( float p, int dim ){ 152 int v = round( (p-bbox.min[dim])/delta + padsize); 153 return myclamp( v, 0, size(dim)); 154 } 155 /// Converts a volumetric offset in a 3D space coordinate off2pos(const Point3i & off,Point3f & pos)156 void off2pos( const Point3i& off, Point3f& pos ){ 157 pos[0] = off2pos( off[0], 0 ); 158 pos[1] = off2pos( off[1], 1 ); 159 pos[2] = off2pos( off[2], 2 ); 160 } 161 /// Converts a volumetric offset in a 3D space coordinate off2pos(int i,int j,int k,Point3f & pos)162 void off2pos( int i, int j, int k, Point3f& pos ){ 163 pos[0] = off2pos( i, 0 ); 164 pos[1] = off2pos( j, 1 ); 165 pos[2] = off2pos( k, 2 ); 166 } 167 /// Converts an offset on grid in object space coordinate off2pos(int i,int dim)168 float off2pos( int i, int dim ){ 169 return (i-padsize)*delta + bbox.min[dim]; 170 } 171 /// Returns the bounding box get_bbox()172 const vcg::Box3f& get_bbox(){ 173 return this->bbox; 174 } 175 /// Returns a string representing the content of the volume at 176 /// a particular slice along dimension dim 177 QString toString(int dim=2, int a=5); 178 }; 179 180 } // end namespace vcg 181 #endif // VOLUME_H 182