Radium Engine  1.5.20
Loading...
Searching...
No Matches
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
13namespace Ra {
14namespace IO {
15
16using namespace Ra::Core;
17using namespace Ra::Core::Utils;
18
19static const std::string volFileExtension { "vol" };
20static const std::string pvmFileExtension { "pvm" };
21
22VolumeLoader::VolumeLoader() = default;
23VolumeLoader::~VolumeLoader() = default;
24
25std::vector<std::string> VolumeLoader::getFileExtensions() const {
26 return { { "*." + volFileExtension }, { "*." + pvmFileExtension } };
27}
28
29bool VolumeLoader::handleFileExtension( const std::string& extension ) const {
30 return ( extension.compare( volFileExtension ) == 0 ) ||
31 ( extension.compare( pvmFileExtension ) == 0 );
32}
33
34Ra::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
42bool 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
51Ra::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
113Ra::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
195Ra::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
203std::string VolumeLoader::name() const {
204 return "VolumeLoader (pbrt experimental, pvm)";
205}
206
207} // namespace IO
208} // namespace Ra
T c_str(T... args)
Discrete volume data storing values in a regular grid.
Definition Volume.hpp:182
T compare(T... args)
T find_last_of(T... args)
T free(T... args)
T generate(T... args)
T is_open(T... args)
T max(T... args)
This namespace contains everything "low level", related to data, datastuctures, and computation.
Definition Cage.cpp:4
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T substr(T... args)