cartodata 6.0.0
volumeformatwriter_d.h
Go to the documentation of this file.
1/* This software and supporting documentation are distributed by
2 * Institut Federatif de Recherche 49
3 * CEA/NeuroSpin, Batiment 145,
4 * 91191 Gif-sur-Yvette cedex
5 * France
6 *
7 * This software is governed by the CeCILL-B license under
8 * French law and abiding by the rules of distribution of free software.
9 * You can use, modify and/or redistribute the software under the
10 * terms of the CeCILL-B license as circulated by CEA, CNRS
11 * and INRIA at the following URL "http://www.cecill.info".
12 *
13 * As a counterpart to the access to the source code and rights to copy,
14 * modify and redistribute granted by the license, users are provided only
15 * with a limited warranty and the software's author, the holder of the
16 * economic rights, and the successive licensors have only limited
17 * liability.
18 *
19 * In this respect, the user's attention is drawn to the risks associated
20 * with loading, using, modifying and/or developing or reproducing the
21 * software by the user in light of its specific status of free software,
22 * that may mean that it is complicated to manipulate, and that also
23 * therefore means that it is reserved for developers and experienced
24 * professionals having in-depth computer knowledge. Users are therefore
25 * encouraged to load and test the software's suitability as regards their
26 * requirements in conditions enabling the security of their systems and/or
27 * data to be ensured and, more generally, to use and operate it in the
28 * same conditions as regards security.
29 *
30 * The fact that you are presently reading this means that you have had
31 * knowledge of the CeCILL-B license and that you accept its terms.
32 */
33
34#ifndef CARTODATA_IO_VOLUMEFORMATWRITER_D_H
35#define CARTODATA_IO_VOLUMEFORMATWRITER_D_H
36//--- cartodata --------------------------------------------------------------
37#include <cartodata/io/volumeformatwriter.h> // class declaration
38#include <cartodata/volume/volume.h> // manipulate sizes
39//--- soma-io ----------------------------------------------------------------
40#include <soma-io/config/soma_config.h>
41#include <soma-io/datasourceinfo/datasourceinfo.h> // function's argument
42#include <soma-io/image/imagewriter.h> // use of member functions
43#include <soma-io/utilities/minfutil.h> // used by filterProperties()
44//--- cartobase --------------------------------------------------------------
45#include <cartobase/smart/rcptr.h>
46#include <cartobase/object/object.h> // header & options
47#include <cartobase/object/property.h> // header & options
48#include <cartobase/exception/ioexcept.h> // exceptions
49//--- system -----------------------------------------------------------------
50#include <vector>
51#include <iostream>
52#include <string>
53//--- debug ------------------------------------------------------------------
54#include <cartobase/config/verbose.h>
55#define localMsg( message ) cartoCondMsg( 4, message, "VOLUMEFORMATWRITER" )
56// localMsg must be undef at end of file
57//----------------------------------------------------------------------------
58
59namespace soma
60{
64
65 //==========================================================================
66 // C O N S T R U C T O R S
67 //==========================================================================
68 template <typename T>
72
73 //==========================================================================
74 // F I L T E R M E T H O D S
75 //==========================================================================
76 template <typename T>
78 carto::Object options)
79 {
80 // Filter minf to remove irrelevant properties
81 soma::MinfUtil::filter(header, options);
82
83 return true;
84 }
85
86 //==========================================================================
87 // W R I T E M E T H O D S
88 //==========================================================================
89 template <typename T>
92 carto::Object options )
93 {
94 localMsg( "writing: " + dsi->url() );
95 //=== memory mapping =====================================================
96 localMsg( "checking for memory mapping..." );
98 return true;
99
100 //=== multiresolution level ==============================================
101 localMsg( "reading resolution level..." );
102 int level = 0;
103 if( options->hasProperty( "resolution_level" ) ) {
104 options->getProperty( "resolution_level", level );
105 if (level < 0) {
106 try {
107 // Try to solve negative level values
108 level += dsi->header()->getProperty( "resolutions_dimension" )
109 ->size();
110 }
111 catch(...){}
112 }
113 }
114 localMsg( " -> level to write : " + carto::toString( level ) );
115
116 //=== partial reading ====================================================
117 localMsg( "checking for partial writing..." );
118 bool partial = false;
119 if( options->hasProperty( "partial_writing" ) )
120 partial = true;
121 if( partial )
122 {
123 localMsg( " -> partial writing enabled." );
124 }
125
126 size_t dim, ndim = obj.getSize().size();
127 std::vector<int> position( ndim, 0 );
128 std::vector<int> view( ndim, 0 );
129 std::vector<int> size( ndim, 1 );
130
131 //=== checking if obj is a view ==========================================
132 localMsg( "checking if object is a view..." );
133 carto::Volume<T> *parent1 = 0;
134 carto::Volume<T> *parent2 = 0;
135 parent1 = obj.refVolume().get();
136 if( parent1 )
137 parent2 = parent1->refVolume().get();
138 localMsg( std::string("object ") + ( parent1 ? "is" : "isn't" ) + " a view and "
139 + ( obj.allocatorContext().isAllocated() ? "is" : "isn't" )
140 + " allocated." );
141 if( parent1 )
142 {
143 localMsg( std::string("parent1 exists and ")
144 + ( parent1->allocatorContext().isAllocated() ? "is" : "isn't" )
145 + " allocated." );
146 }
147 if( parent2 )
148 {
149 localMsg( std::string("parent2 exists and ")
150 + ( parent2->allocatorContext().isAllocated() ? "is" : "isn't" )
151 + " allocated." );
152 }
153
154 //=== view size ==========================================================
155 localMsg( "reading view size..." );
156 view = obj.getSize();
157
158 //=== full volume size ===================================================
159 localMsg( "reading full volume size and view position..." );
160 if( parent1 && !parent1->allocatorContext().isAllocated() ) {
161 localMsg( " -> from parent1" )
162 size = parent1->getSize();
163 position = obj.posInRefVolume();
164 } else if( parent2 ) {
165 localMsg( " -> from parent2" )
166 size = parent2->getSize();
167 position = obj.posInRefVolume();
168 size_t i, rndim = parent1->posInRefVolume().size();
169 if( position.size() < rndim )
170 position.resize( rndim, 0 );
171 for( i=0; i<rndim; ++i )
172 position[ i ] += parent1->posInRefVolume()[ i ];
173 } else {
174 localMsg( " -> from self" )
175 size = view;
176 }
177
178 if( !partial ) {
179 // we treat the view as a pure Volume
180 localMsg( " -> from self (no partial writing)" )
181 size = view;
182 position = std::vector<int>( ndim, 0 );
183 }
184
185 localMsg( " -> Full volume size : ( "
186 + carto::toString( size[0] ) + ", "
187 + carto::toString( size[1] ) + ", "
188 + carto::toString( size[2] ) + ", "
189 + carto::toString( size[3] ) + " )" );
190 localMsg( " -> View size : ( "
191 + carto::toString( view[0] ) + ", "
192 + carto::toString( view[1] ) + ", "
193 + carto::toString( view[2] ) + ", "
194 + carto::toString( view[3] ) + " )" );
195 localMsg( " -> View position : ( "
196 + carto::toString( position[0] ) + ", "
197 + carto::toString( position[1] ) + ", "
198 + carto::toString( position[2] ) + ", "
199 + carto::toString( position[3] ) + " )" );
200
201 //=== checking for borders ===============================================
202 localMsg( "checking for borders..." );
203 bool withborders = false;
204 if( parent1 && parent1->allocatorContext().isAllocated() )
205 withborders = true;
206 localMsg( std::string(" -> ") + ( withborders ? "with borders" : "without borders" ) );
207 withborders = withborders; // compilation warning
208
209 // handle internal orientation: go back to LPI
210 const Referential & ref = obj.referential();
211 std::vector<int> odim = obj.getSize();
212 std::vector<float> osz( odim.begin(), odim.end() );
213 for( dim=0; dim<osz.size(); ++dim )
214 --osz[dim];
215 rc_ptr<Transformation> tolpir = ref.toOrientation( "LPI", osz );
217 = dynamic_cast<AffineTransformationBase &>( *tolpir );
218 std::unique_ptr<AffineTransformationBase> itolpi = tolpi.inverse();
219
220 std::vector<int> lpi_size = tolpi.transformVector( size );
221 for( dim=0; dim<lpi_size.size(); ++dim )
222 lpi_size[dim] = std::abs( lpi_size[dim] );
223
224 //=== header info ========================================================
225 localMsg( "setting header..." );
226 if( !options )
228 if( !parent1 && !obj.allocatorContext().isAllocated() )
229 options->setProperty( "unallocated", true );
230 if( !dsi->header() )
231 {
232 dsi->header() = carto::Object::value( carto::PropertySet() );
233 Object lpi_header = obj.reorientedHeader( "LPI" );
234 dsi->header()->copyProperties( lpi_header );
235 std::vector<int> size;
236 lpi_header->getProperty( "volume_dimension", size );
237 dsi->header()->setProperty( "sizeX", size[0] );
238 dsi->header()->setProperty( "sizeY", size[1] );
239 dsi->header()->setProperty( "sizeZ", size[2] );
240 dsi->header()->setProperty( "sizeT", size[3] );
241 }
242
243 //=== use optional parameters for partial writing ========================
244 if( partial ) {
245 try {
246 position[0] = (int) rint( options->getProperty( "ox" )->getScalar() );
247 localMsg( "override ox : " + carto::toString(position[0]) );
248 } catch( ... ) {}
249 try {
250 position[1] = (int) rint( options->getProperty( "oy" )->getScalar() );
251 localMsg( "override oy : " + carto::toString(position[1]) );
252 } catch( ... ) {}
253 try {
254 position[2] = (int) rint( options->getProperty( "oz" )->getScalar() );
255 localMsg( "override oz : " + carto::toString(position[2]) );
256// std::cout << "override oz : " + carto::toString(position[2]) << std::endl;
257 } catch( ... ) {}
258 try {
259 position[3] = (int) rint( options->getProperty( "ot" )->getScalar() );
260 localMsg( "override ot : " + carto::toString(position[3]) );
261// std::cout << "override ot : " + carto::toString(position[3]) << std::endl;
262 } catch( ... ) {}
263 size_t dim, value;
264 for( dim=0; dim<carto::Volume<T>::DIM_MAX; ++dim )
265 {
266 try
267 {
268 std::stringstream skey;
269 skey << "ox" << dim+1;
270 std::string key = skey.str();
271 value = (int) rint( options->getProperty( key )->getScalar() );
272 options->removeProperty( key );
273 while( position.size() <= dim )
274 position.push_back( 0 );
275 position[ dim ] = value;
276// std::cout << "override " << key << " : " + carto::toString(value) << std::endl;
277 }
278 catch( ... ) {}
279 }
280 }
281
282 //=== writing header & creating files ====================================
283 localMsg( "writing header..." );
284 std::vector<long> strides( ndim );
285 for( dim=0; dim<ndim; ++dim )
286 {
287 std::vector<int> pos( ndim, 0 );
288 pos[dim] = 1;
289 strides[dim] = &obj( pos ) - &obj(0,0,0,0);
290 }
291
292 this->filterProperties(dsi->header(), options);
293
294 // handle internal orientation: go back to LPI
295 std::vector<int> opos = position;
296 std::vector<int> oview = view;
297 const T* start = &obj(0);
298 {
299 opos = tolpi.transformVector( position );
300 std::vector<int> p = std::vector<int>( ndim, 0 );
301 std::vector<int> pi = itolpi->transform( p );
302 start = &obj( pi );
303 oview = tolpi.transformVector( view );
304 for( dim=0; dim<oview.size(); ++dim )
305 oview[dim] = std::abs( oview[dim] );
306 for( dim=0; dim<ndim; ++dim )
307 {
308 p[dim] = 1;
309 pi = itolpi->transformVector( p );
310 strides[dim] = &obj.at( pi ) - &obj.at( 0 );
311 p[dim] = 0;
312 }
313 }
314
315 *dsi = _imw->writeHeader( *dsi, start, opos, oview,
316 strides, options );
317
318 //=== sanity check =======================================================
319 if( partial )
320 {
321 // file sizes may be different from what has been set before (since
322 // the file already exists, its size has been re-read by writeHeader())
323 std::vector<int> file_sz( ndim, 1 );
324 if( !dsi->header()->getProperty( "volume_dimension", file_sz ) )
325 {
326 dsi->header()->getProperty( "sizeX", file_sz[0] );
327 dsi->header()->getProperty( "sizeY", file_sz[1] );
328 dsi->header()->getProperty( "sizeZ", file_sz[2] );
329 dsi->header()->getProperty( "sizeT", file_sz[3] );
330 }
331 for( dim=0; dim<ndim; ++dim )
332 {
333 if( file_sz.size() <= dim )
334 file_sz.push_back( 1 );
335 if( opos[dim] + oview[dim] > file_sz[dim] )
336 {
337 localMsg( "view is larger than the volume." );
338 throw carto::format_error( "view is larger than the volume." );
339 }
340 }
341 }
342
343 //=== writing image ======================================================
344 localMsg( "writing volume..." );
345 const T* data = 0;
346 if( parent1 || obj.allocatorContext().isAllocated() )
347 data = start;
348
349 // in unallocated case, data is null; this is OK.
350 _imw->write( data, *dsi, opos, oview, strides, options );
351// {
352// // if( !withborders ) {
353// _imw->write( (T*) &obj(0,0,0,0), *dsi, position, view, strides,
354// options );
355// // } else {
356// // int y, z, t;
357// // std::vector<int> posline ( position );
358// // std::vector<int> sizeline ( 4, 1 );
359// // sizeline[ 0 ] = view[ 0 ];
360// // for( t=0; t<view[3]; ++t )
361// // for( z=0; z<view[2]; ++z )
362// // for( y=0; y<view[1]; ++y ) {
363// // posline[ 1 ] = position[ 1 ] + y;
364// // posline[ 2 ] = position[ 2 ] + z;
365// // posline[ 3 ] = position[ 3 ] + t;
366// // _imw->write( (T*) &obj(0,y,z,t), *dsi, posline,
367// // sizeline, options );
368// // }
369// // }
370// }
371 // else we just needed to write the header and reserve file space
372 // no image to write
373
374 // we reset at 0 the ImageWriter's members (sizes, binary, ...) so that
375 // they are recomputed at the next writing.
376 _imw->resetParams();
377
378 localMsg( "writing done." );
379
380 return true;
381 }
382
383 template <typename T>
388
392
393 template <typename T>
397
398 template <typename T>
400 carto::Object options)
401 {
402 // Filter minf to remove irrelevant properties
403 soma::MinfUtil::filter(header, options);
404
405 return true;
406 }
407
408
409 template <typename T>
412 carto::Object options )
413 {
415 vfw.attach( _imw );
416 return vfw.write( *obj, dsi, options );
417 }
418
419 template <typename T>
424
425}
426
427#undef localMsg
428#endif
static Object value()
std::vector< int > getSize() const
get the 4 dimensions in a vector
Convenient handle for a Volume - this is normally the entry point for all volumes handling.
Definition volumeref.h:60
N-D Volume main class.
Definition volumebase.h:120
const Referential & referential() const
Referential and orientation information.
const AllocatorContext & allocatorContext() const
returns volume's AllocatorContext
Object reorientedHeader(const std::string &orient) const
used by flipToOrientation(), reorient header information
const Position & posInRefVolume() const
Get position in parent volume.
rc_ptr< Volume< T > > refVolume() const
Get parent volume.
const T & at(long x, long y=0, long z=0, long t=0) const
T * get() const
std::unique_ptr< AffineTransformationBase > inverse() const
MappingMode allocatorType() const
bool isAllocated() const
static void filter(carto::Object header, carto::Object options=carto::none())
virtual std::vector< double > transformVector(const std::vector< double > &pos) const
FormatWriter specialized for 4D Volume.
virtual bool filterProperties(carto::Object header, carto::Object options=carto::none())
FormatWriter derived function It removes properties that must not be written.
carto::rc_ptr< ImageWriter< T > > _imw
virtual bool write(const carto::Volume< T > &obj, carto::rc_ptr< DataSourceInfo > dsi, carto::Object options)
FormatWriter derived function This method understands a volume and calls appropriate ImageWriter meth...
void attach(carto::rc_ptr< ImageWriter< T > > imw)
Linking to a ImageWriter Allows us to declare only once the ImageWriter.
carto::rc_ptr< ImageWriter< T > > _imw
virtual bool filterProperties(carto::Object header, carto::Object options=carto::none())
FormatWriter derived function It removes properties that must not be written.
virtual bool write(const carto::VolumeRef< T > &obj, carto::rc_ptr< DataSourceInfo > dsi, carto::Object options)
FormatWriter derived function This method understands a volume and calls appropriate ImageWriter meth...
void attach(carto::rc_ptr< ImageWriter< T > > imw)
Linking to a ImageWriter Allows us to declare only once the ImageWriter.
std::string toString(const T &object)
#define localMsg(message)