cartodata  5.1.2
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 ----------------------------------------------------------------
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 ------------------------------------------------------------------
55 #define localMsg( message ) cartoCondMsg( 4, message, "VOLUMEFORMATWRITER" )
56 // localMsg must be undef at end of file
57 //----------------------------------------------------------------------------
58 
59 namespace soma
60 {
64 
65  //==========================================================================
66  // C O N S T R U C T O R S
67  //==========================================================================
68  template <typename T>
70  {
71  }
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  //=== header info ========================================================
210  localMsg( "setting header..." );
211  if( !options )
213  if( !parent1 && !obj.allocatorContext().isAllocated() )
214  options->setProperty( "unallocated", true );
215  if( !dsi->header() )
216  {
217  dsi->header() = carto::Object::value( carto::PropertySet() );
218  dsi->header()->copyProperties(
219  carto::Object::reference( obj.header() ) );
220  }
221  dsi->header()->setProperty( "volume_dimension", size );
222  dsi->header()->setProperty( "sizeX", size[ 0 ] );
223  dsi->header()->setProperty( "sizeY", size[ 1 ] );
224  dsi->header()->setProperty( "sizeZ", size[ 2 ] );
225  dsi->header()->setProperty( "sizeT", size[ 3 ] );
226  if( !dsi->header()->hasProperty( "voxel_size" ) )
227  {
228  std::vector<float> voxel_size( 4, 1. );
229  dsi->header()->setProperty( "voxel_size", voxel_size );
230  }
231 
232 
233  //=== use optional parameters for partial writing ========================
234  if( partial ) {
235  try {
236  position[0] = (int) rint( options->getProperty( "ox" )->getScalar() );
237  localMsg( "override ox : " + carto::toString(position[0]) );
238  } catch( ... ) {}
239  try {
240  position[1] = (int) rint( options->getProperty( "oy" )->getScalar() );
241  localMsg( "override oy : " + carto::toString(position[1]) );
242  } catch( ... ) {}
243  try {
244  position[2] = (int) rint( options->getProperty( "oz" )->getScalar() );
245  localMsg( "override oz : " + carto::toString(position[2]) );
246 // std::cout << "override oz : " + carto::toString(position[2]) << std::endl;
247  } catch( ... ) {}
248  try {
249  position[3] = (int) rint( options->getProperty( "ot" )->getScalar() );
250  localMsg( "override ot : " + carto::toString(position[3]) );
251 // std::cout << "override ot : " + carto::toString(position[3]) << std::endl;
252  } catch( ... ) {}
253  size_t dim, value;
254  for( dim=0; dim<carto::Volume<T>::DIM_MAX; ++dim )
255  {
256  try
257  {
258  std::stringstream skey;
259  skey << "ox" << dim+1;
260  std::string key = skey.str();
261  value = (int) rint( options->getProperty( key )->getScalar() );
262  options->removeProperty( key );
263  while( position.size() <= dim )
264  position.push_back( 0 );
265  position[ dim ] = value;
266 // std::cout << "override " << key << " : " + carto::toString(value) << std::endl;
267  }
268  catch( ... ) {}
269  }
270  }
271 
272  //=== writing header & creating files ====================================
273  localMsg( "writing header..." );
274  std::vector<long> strides( ndim );
275  for( dim=0; dim<ndim; ++dim )
276  {
277  std::vector<int> pos( ndim, 0 );
278  pos[dim] = 1;
279  strides[dim] = &obj( pos ) - &obj(0,0,0,0);
280  }
281 
282  this->filterProperties(dsi->header(), options);
283 
284 
285  *dsi = _imw->writeHeader( *dsi, (T*) &obj(0,0,0,0), position, view,
286  strides, options );
287 
288  //=== sanity check =======================================================
289  if( partial )
290  {
291  // file sizes may be different from what has been set before (since
292  // the file already exists, its size has been re-read by writeHeader())
293  std::vector<int> file_sz( ndim, 1 );
294  if( !dsi->header()->getProperty( "volume_dimension", file_sz ) )
295  {
296  dsi->header()->getProperty( "sizeX", file_sz[0] );
297  dsi->header()->getProperty( "sizeY", file_sz[1] );
298  dsi->header()->getProperty( "sizeZ", file_sz[2] );
299  dsi->header()->getProperty( "sizeT", file_sz[3] );
300  }
301  for( dim=0; dim<ndim; ++dim )
302  {
303  if( file_sz.size() <= dim )
304  file_sz.push_back( 1 );
305  if( position[dim] + view[dim] > file_sz[dim] )
306  {
307  localMsg( "view is larger than the volume." );
308  throw carto::format_error( "view is larger than the volume." );
309  }
310  }
311  }
312 
313  //=== writing image ======================================================
314  localMsg( "writing volume..." );
315  const T* data = 0;
316  if( parent1 || obj.allocatorContext().isAllocated() )
317  data = reinterpret_cast<const T*>( &obj(0,0,0,0) );
318  // in unallocated case, data is null; this is OK.
319  _imw->write( data, *dsi, position, view, strides, options );
320 // {
321 // // if( !withborders ) {
322 // _imw->write( (T*) &obj(0,0,0,0), *dsi, position, view, strides,
323 // options );
324 // // } else {
325 // // int y, z, t;
326 // // std::vector<int> posline ( position );
327 // // std::vector<int> sizeline ( 4, 1 );
328 // // sizeline[ 0 ] = view[ 0 ];
329 // // for( t=0; t<view[3]; ++t )
330 // // for( z=0; z<view[2]; ++z )
331 // // for( y=0; y<view[1]; ++y ) {
332 // // posline[ 1 ] = position[ 1 ] + y;
333 // // posline[ 2 ] = position[ 2 ] + z;
334 // // posline[ 3 ] = position[ 3 ] + t;
335 // // _imw->write( (T*) &obj(0,y,z,t), *dsi, posline,
336 // // sizeline, options );
337 // // }
338 // // }
339 // }
340  // else we just needed to write the header and reserve file space
341  // no image to write
342 
343  // we reset at 0 the ImageWriter's members (sizes, binary, ...) so that
344  // they are recomputed at the next writing.
345  _imw->resetParams();
346  return true;
347  }
348 
349  template <typename T>
351  {
352  _imw = imw;
353  }
354 
358 
359  template <typename T>
361  {
362  }
363 
364  template <typename T>
366  carto::Object options)
367  {
368  // Filter minf to remove irrelevant properties
369  soma::MinfUtil::filter(header, options);
370 
371  return true;
372  }
373 
374 
375  template <typename T>
378  carto::Object options )
379  {
381  vfw.attach( _imw );
382  return vfw.write( *obj, dsi, options );
383  }
384 
385  template <typename T>
387  {
388  _imw = imw;
389  }
390 
391 }
392 
393 #undef localMsg
394 #endif
const PropertySet & header() const
Object reference(Object &value)
static Object value()
std::vector< int > getSize() const
get the 4 dimensions in a vector
Definition: volumeproxy.h:129
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:119
const AllocatorContext & allocatorContext() const
returns volume's AllocatorContext
Definition: volumebase_d.h:521
const Position & posInRefVolume() const
Get position in parent volume.
Definition: volumebase_d.h:533
rc_ptr< Volume< T > > refVolume() const
Get parent volume.
Definition: volumebase_d.h:527
T * get() const
MappingMode allocatorType() const
bool isAllocated() const
static void filter(carto::Object header, carto::Object options=carto::none())
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.
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.
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)