Radium Engine  1.5.0
VolumeLoader.cpp
1 #include <IO/VolumesLoader/VolumeLoader.hpp>
2 
3 #include <IO/VolumesLoader/pvmutils.hpp>
4 
5 #include <Core/Asset/FileData.hpp>
6 #include <Core/Geometry/Volume.hpp>
7 #include <Core/Utils/Log.hpp>
8 
9 #include <algorithm>
10 #include <fstream>
11 #include <iostream>
12 
13 namespace Ra {
14 namespace IO {
15 
16 using namespace Ra::Core;
17 using namespace Ra::Core::Utils;
18 
19 static const std::string volFileExtension { "vol" };
20 static const std::string pvmFileExtension { "pvm" };
21 
22 VolumeLoader::VolumeLoader() = default;
23 VolumeLoader::~VolumeLoader() = default;
24 
25 std::vector<std::string> VolumeLoader::getFileExtensions() const {
26  return { { "*." + volFileExtension }, { "*." + pvmFileExtension } };
27 }
28 
29 bool VolumeLoader::handleFileExtension( const std::string& extension ) const {
30  return ( extension.compare( volFileExtension ) == 0 ) ||
31  ( extension.compare( pvmFileExtension ) == 0 );
32 }
33 
34 Ra::Core::Utils::Color readColor( std::ifstream& input, std::string& name ) {
35  char beg, end;
36  Scalar r, g, b;
37  input >> name >> beg >> r >> g >> b >> end;
38  if ( beg == '[' && end == ']' ) { return Ra::Core::Utils::Color( r, g, b ); }
39  return Ra::Core::Utils::Color( 0, 0, 0 );
40 }
41 
42 bool checkExpected( const std::string& expected, const std::string& found ) {
43  if ( expected != found ) {
44  LOG( logWARNING ) << "\tVolumeLoader : unexpected volume attribute " << found << " : "
45  << expected << " was expected";
46  return false;
47  }
48  return true;
49 }
50 
51 Ra::Core::Asset::FileData* VolumeLoader::loadVolFile( const std::string& filename ) {
52  LOG( logINFO ) << "VolumeLoader : loading vol (pbrt based) file " << filename;
53  std::ifstream input( filename );
54  if ( input.is_open() ) {
55  auto fileData = new Ra::Core::Asset::FileData( filename );
56  std::string attribname;
57  auto sigma_a = readColor( input, attribname );
58  if ( !checkExpected( "sigma_a", attribname ) ) { return nullptr; }
59  auto sigma_s = readColor( input, attribname );
60  if ( !checkExpected( "sigma_s", attribname ) ) { return nullptr; }
61 
62  char beg, end;
63  int sx, sy, sz;
64 
65  input >> attribname >> beg >> sx >> sy >> sz >> end;
66  if ( !checkExpected( "size", attribname ) ) { return nullptr; }
67 
68  input >> attribname >> beg;
69  if ( !checkExpected( "density", attribname ) ) { return nullptr; }
70  if ( beg != '[' ) {
71  LOG( logWARNING ) << "\tVolumeLoader : unexpected start of density gri delimiter "
72  << beg;
73  return nullptr;
74  }
75  LOG( logINFO ) << "\tVolumeLoader : reading a volume of size " << sx << "x" << sy << "x"
76  << sz;
77 
78  Ra::Core::Vector3 voxelSize { 1_ra, 1_ra, 1_ra };
79  auto density = new Geometry::VolumeGrid();
80  density->setSize( Vector3i( sx, sy, sz ) );
81  density->setBinSize( voxelSize );
82  std::generate( density->data().begin(), density->data().end(), [&input]() {
83  Scalar v;
84  input >> v;
85  return v;
86  } );
87 
88  input >> end;
89  if ( end != ']' ) {
90  LOG( logWARNING ) << "\tVolumeLoader : unexpected end of density grid delimiter "
91  << end;
92  return nullptr;
93  }
94  LOG( logINFO ) << "\tVolumeLoader : done reading";
95 
96  auto volume = new Asset::VolumeData( filename.substr( filename.find_last_of( '/' ) + 1 ) );
97  volume->volume = density;
98  volume->sigma_a = sigma_a;
99  volume->sigma_s = sigma_s;
100  Scalar maxDim = std::max( std::max( sx, sy ), sz );
101  Ra::Core::Vector3 p0( 0, 0, 0 );
102  Ra::Core::Vector3 p1( sx, sy, sz );
103  volume->boundingBox = Aabb( p0, p1 );
104  volume->densityToModel = Transform::Identity(); // Eigen::Scaling( 1_ra / maxDim );
105  volume->modelToWorld = Eigen::Scaling( 1_ra / maxDim ); // Transform::Identity();
106  fileData->m_volumeData.push_back( std::unique_ptr<Ra::Core::Asset::VolumeData>( volume ) );
107  return fileData;
108  }
109  LOG( logWARNING ) << "VolumeLoader : unable to open file " << filename;
110  return nullptr;
111 }
112 
113 Ra::Core::Asset::FileData* VolumeLoader::loadPvmFile( const std::string& filename ) {
114  using namespace PVMVolume;
115 
116  unsigned int width, height, depth, bytePerVoxel;
117  float scalex, scaley, scalez;
118  unsigned char *description, *courtesy, *parameter, *comment;
119 
120  auto volumeData = readPVMvolume( filename.c_str(),
121  &width,
122  &height,
123  &depth,
124  &bytePerVoxel,
125  &scalex,
126  &scaley,
127  &scalez,
128  &description,
129  &courtesy,
130  &parameter,
131  &comment );
132  if ( volumeData ) {
133  {
134  unsigned char empty[1] { '\0' };
135  LOG( logINFO ) << "VolumeLoader : \n\tpvm (The Volume Library) file " << filename
136  << " \n\twidth = " << width << " \n\theight = " << height
137  << " \n\tdepth = " << depth << " \n\tbyte per voxel = " << bytePerVoxel
138  << " \n\tscalex = " << scalex << " \n\tscaley = " << scaley
139  << " \n\tscalez = " << scalez
140  << " \n\tdescription = " << ( description ? description : empty )
141  << " \n\tcourtesy = " << ( courtesy ? courtesy : empty )
142  << " \n\tparameter = " << ( parameter ? parameter : empty )
143  << " \n\tcomment = " << ( comment ? comment : empty ) << '\n';
144  }
145  auto fillRadiumVolume = []( auto container, auto densityData ) {
146  std::generate( container->data().begin(), container->data().end(), [&densityData]() {
147  auto d = *densityData++;
148  return Scalar( d ) / Scalar( std::numeric_limits<decltype( d )>::max() );
149  } );
150  };
151  Ra::Core::Vector3 binSize { Scalar( scalex ), Scalar( scaley ), Scalar( scalez ) };
152  Ra::Core::Vector3i gridSize { int( width ), int( height ), int( depth ) };
153  auto density = new Geometry::VolumeGrid();
154  density->setSize( gridSize );
155  density->setBinSize( binSize );
156 
157  switch ( bytePerVoxel ) {
158  case 1: {
159  fillRadiumVolume( density, volumeData );
160  break;
161  }
162  case 2: {
163  fillRadiumVolume( density, (uint16_t*)( volumeData ) );
164  break;
165  }
166  case 4: {
167  fillRadiumVolume( density, (uint*)( volumeData ) );
168  break;
169  }
170  default:
171  LOG( logERROR ) << "VolumeLoader : unsupported number of componenets : "
172  << bytePerVoxel;
173  }
174  free( volumeData );
175 
176  LOG( logINFO ) << "\tVolumeLoader : done reading";
177 
178  auto volume = new Asset::VolumeData( filename.substr( filename.find_last_of( '/' ) + 1 ) );
179  volume->volume = density;
180  Scalar maxDim = std::max( std::max( width, height ), depth );
181  Ra::Core::Vector3 p0 = Vector3::Zero();
182  Ra::Core::Vector3 p1 = gridSize.cast<Scalar>().cwiseProduct( binSize );
183  volume->boundingBox = Aabb( p0, p1 );
184  volume->densityToModel = Eigen::Scaling( binSize );
185  volume->modelToWorld = Eigen::Scaling( 1_ra / maxDim ) * Translation( p1 * -0.5 );
186 
187  auto fileData = new Ra::Core::Asset::FileData( filename );
188  fileData->m_volumeData.push_back( std::unique_ptr<Ra::Core::Asset::VolumeData>( volume ) );
189  return fileData;
190  }
191  LOG( logWARNING ) << "VolumeLoader : unable to open file " << filename;
192  return nullptr;
193 }
194 
195 Ra::Core::Asset::FileData* VolumeLoader::loadFile( const std::string& filename ) {
196  std::string extension = filename.substr( filename.find_last_of( '.' ) + 1 );
197  if ( extension.compare( volFileExtension ) == 0 ) { return loadVolFile( filename ); }
198  else if ( extension.compare( pvmFileExtension ) == 0 ) { return loadPvmFile( filename ); }
199  LOG( logWARNING ) << "VolumeLoader : unsupported file format : " << filename;
200  return nullptr;
201 }
202 
203 std::string VolumeLoader::name() const {
204  return "VolumeLoader (pbrt experimental, pvm)";
205 }
206 
207 } // namespace IO
208 } // namespace Ra
Discrete volume data storing values in a regular grid.
Definition: Volume.hpp:182
Definition: Cage.cpp:3