cartodata  4.7.0
volumeutilio_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 #ifndef CARTODATA_IO_VOLUMEUTILIO_D_H
34 #define CARTODATA_IO_VOLUMEUTILIO_D_H
35 
36 //--- cartodata --------------------------------------------------------------
37 #include <cartodata/io/volumeutilio.h> // class definition
39 //--- soma-io ----------------------------------------------------------------
40 #include <soma-io/config/soma_config.h> // (#define soma)
41 #include <soma-io/io/reader.h>
44 //--- cartobase --------------------------------------------------------------
45 #include <cartobase/object/object.h> // header, options
46 #include <cartobase/object/property.h> // header, options
47 //--- system -----------------------------------------------------------------
48 #include <vector> // 4D vectors
49 #include <set> // properties list
50 //--- debug ------------------------------------------------------------------
52 #define localMsg( message ) cartoCondMsg( 3, message, "VOLUMEUTILIO" )
53 // localMsg must be undef at end of file
54 //----------------------------------------------------------------------------
55 
56 namespace soma {
57 
58  template <typename T> std::set<std::string>
60  {
61  std::set<std::string> properties;
62  properties.insert( "ox" );
63  properties.insert( "oy" );
64  properties.insert( "oz" );
65  properties.insert( "ot" );
66  properties.insert( "sx" );
67  properties.insert( "sy" );
68  properties.insert( "sz" );
69  properties.insert( "st" );
70  properties.insert( "bx" );
71  properties.insert( "by" );
72  properties.insert( "bz" );
73  properties.insert( "border" );
74  properties.insert( "ox1" );
75  properties.insert( "ox1" );
76  properties.insert( "ox2" );
77  properties.insert( "ox3" );
78  properties.insert( "ox4" );
79  properties.insert( "ox5" );
80  properties.insert( "ox6" );
81  properties.insert( "ox7" );
82  properties.insert( "ox8" );
83  properties.insert( "sx1" );
84  properties.insert( "sx2" );
85  properties.insert( "sx3" );
86  properties.insert( "sx4" );
87  properties.insert( "sx5" );
88  properties.insert( "sx6" );
89  properties.insert( "sx7" );
90  properties.insert( "sx8" );
91  return properties;
92  }
93 
94  //==========================================================================
95  // R E A D
96  //==========================================================================
97 
98  template <typename T> carto::Volume<T>*
101  carto::Object options )
102  {
103  std::vector<int> position( 4, 0 );
104  std::vector<int> frame( 4, 0 );
105  std::vector<int> borders( 4, 0 );
106  try {
107  position[0] = (int) rint(options->getProperty( "ox" )->getScalar() );
108  options->removeProperty( "ox" );
109  } catch( ... ) {}
110  try {
111  position[1] = (int) rint( options->getProperty( "oy" )->getScalar() );
112  options->removeProperty( "oy" );
113  } catch( ... ) {}
114  try {
115  position[2] = (int) rint( options->getProperty( "oz" )->getScalar() );
116  options->removeProperty( "oz" );
117  } catch( ... ) {}
118  try {
119  position[3] = (int) rint( options->getProperty( "ot" )->getScalar() );
120  options->removeProperty( "ot" );
121  } catch( ... ) {}
122  try {
123  frame[0] = (int) rint( options->getProperty( "sx" )->getScalar() );
124  options->removeProperty( "sx" );
125  } catch( ... ) {}
126  try {
127  frame[1] = (int) rint( options->getProperty( "sy" )->getScalar() );
128  options->removeProperty( "sy" );
129  } catch( ... ) {}
130  try {
131  frame[2] = (int) rint( options->getProperty( "sz" )->getScalar() );
132  options->removeProperty( "sz" );
133  } catch( ... ) {}
134  try {
135  frame[3] = (int) rint( options->getProperty( "st" )->getScalar() );
136  options->removeProperty( "st" );
137  } catch( ... ) {}
138  try {
139  borders[0] = (int) rint( options->getProperty( "border" )->getScalar() );
140  borders[1] = (int) rint( options->getProperty( "border" )->getScalar() );
141  borders[2] = (int) rint( options->getProperty( "border" )->getScalar() );
142  options->removeProperty( "border" );
143  } catch( ... ) {}
144  try {
145  borders[0] = (int) rint( options->getProperty( "bx" )->getScalar() );
146  options->removeProperty( "bx" );
147  } catch( ... ) {}
148  try {
149  borders[1] = (int) rint( options->getProperty( "by" )->getScalar() );
150  options->removeProperty( "by" );
151  } catch( ... ) {}
152  try {
153  borders[2] = (int) rint( options->getProperty( "bz" )->getScalar() );
154  options->removeProperty( "bz" );
155  } catch( ... ) {}
156 
157  size_t dim, value;
158  for( dim=0; dim<carto::Volume<T>::DIM_MAX; ++dim )
159  {
160  try
161  {
162  std::stringstream skey;
163  skey << "ox" << dim+1;
164  std::string key = skey.str();
165  value = (int) rint( options->getProperty( key )->getScalar() );
166  options->removeProperty( key );
167  if( position.size() <= dim )
168  position.resize( dim + 1, 0 );
169  position[ dim ] = value;
170  }
171  catch( ... ) {}
172  try
173  {
174  std::stringstream skey;
175  skey << "sx" << dim+1;
176  std::string key = skey.str();
177  value = (int) rint( options->getProperty( key )->getScalar() );
178  options->removeProperty( key );
179  if( frame.size() <= dim )
180  frame.resize( dim + 1, 0 );
181  frame[ dim ] = value;
182  }
183  catch( ... ) {}
184  }
185 
186  bool partial = false;
187  for( dim=0; !partial && dim<position.size(); ++dim )
188  if( position[dim] != 0 )
189  partial = true;
190  for( dim=0; !partial && dim<frame.size(); ++dim )
191  if( frame[dim] != 0 )
192  partial = true;
193 
194  if( partial )
195  return readPartial( obj, dsi, position, frame, borders, options );
196  else
197  return readFull( obj, dsi, borders, options );
198  }
199 
200  template <typename T> carto::Volume<T>*
203  std::vector<int> borders,
204  carto::Object options )
205  {
206  //=== VARIABLES ==========================================================
207  //int verbose = carto::debugMessageLevel;
208  carto::Object newoptions;
211  carto::VolumeRef<T> bordersVolume;
212  std::vector<int> fullsize;
213  std::vector<int> bordersize;
214  std::vector<int> volumepos;
215 
216  if( borders[0] !=0 || borders[1] !=0 || borders[2] !=0 )
217  {
218  //=== CHECK FULL VOLUME ================================================
219  localMsg( "=== READING FULL VOLUME SIZE" );
220  newoptions = carto::Object::value( carto::PropertySet() );
221  newoptions->copyProperties( options );
222  localMsg( "checking full volume..." );
223  *dsi = dsil.check( *dsi, options );
224  localMsg( "reading size..." );
225  if( !dsi->header()->getProperty( "volume_dimension", fullsize ) )
226  {
227  fullsize[0] = (int) rint(
228  dsi->header()->getProperty( "sizeX" )->getScalar() );
229  fullsize[1] = (int) rint(
230  dsi->header()->getProperty( "sizeY" )->getScalar() );
231  fullsize[2] = (int) rint(
232  dsi->header()->getProperty( "sizeZ" )->getScalar() );
233  fullsize[3] = (int) rint(
234  dsi->header()->getProperty( "sizeT" )->getScalar() );
235  }
236  if( fullsize.size() < 4 )
237  fullsize.resize( 4, 1 );
238  volumepos.resize( fullsize.size(), 0 );
239  volumepos[0] = borders[0];
240  volumepos[1] = borders[1];
241  volumepos[2] = borders[2];
242  localMsg( "-> size = ( "
243  + carto::toString( fullsize[0] ) + ", "
244  + carto::toString( fullsize[1] ) + ", "
245  + carto::toString( fullsize[2] ) + ", "
246  + carto::toString( fullsize[3] ) + " )"
247  );
248 
249  //=== BORDERS VOLUME ===================================================
250  localMsg( "=== ALLOCATED BORDERS VOLUME" );
251  localMsg( "computing sizes..." );
252  bordersize = fullsize;
253  bordersize[0] = fullsize[0] + 2*borders[0];
254  bordersize[1] = fullsize[1] + 2*borders[1];
255  bordersize[2] = fullsize[2] + 2*borders[2];
256  localMsg( "creating allocated volume..." );
257  localMsg( "-> with size ( "
258  + carto::toString( bordersize[0] ) + ", "
259  + carto::toString( bordersize[1] ) + ", "
260  + carto::toString( bordersize[2] ) + ", "
261  + carto::toString( bordersize[3] ) + " )"
262  );
263  bordersVolume = carto::VolumeRef<T>(
264  new carto::Volume<T>( bordersize ) );
265 
266  //=== READ FULL VOLUME =================================================
267  localMsg( "=== UNALLOCATED FULL VIEW" );
268  rVol = soma::Reader< carto::Volume<T> >( dsi );
269  newoptions = carto::Object::value( carto::PropertySet() );
270  newoptions->copyProperties( options );
271  newoptions->setProperty( "keep_allocation", true );
272  rVol.setOptions( newoptions );
273  localMsg( "creating volume view..." );
274  localMsg( "-> with pos ( "
275  + carto::toString( volumepos[0] ) + ", "
276  + carto::toString( volumepos[1] ) + ", "
277  + carto::toString( volumepos[2] ) + ", "
278  + carto::toString( volumepos[3] ) + " )"
279  );
280  localMsg( "-> with size ( "
281  + carto::toString( fullsize[0] ) + ", "
282  + carto::toString( fullsize[1] ) + ", "
283  + carto::toString( fullsize[2] ) + ", "
284  + carto::toString( fullsize[3] ) + " )"
285  );
286  if( obj )
287  *obj = carto::Volume<T>( bordersVolume, volumepos, fullsize );
288  else
289  obj = new carto::Volume<T>( bordersVolume, volumepos, fullsize );
290  localMsg( "reading unallocated volume..." );
291  rVol.setAllocatorContext( obj->allocatorContext() );
292  rVol.read( *obj );
293 
294  /* copy voxel_size to underlying volume, if any.
295  This should probably be more general, but cannot be applied to all
296  header properties (size, transformations...).
297  WARNING: Moreover here we do not guarantee to keep both voxel_size
298  unique: we point to the same vector of values for now, but it can be
299  replaced (thus, duplicated) by a setProperty().
300  We could use a addBuiltinProperty(), but then the voxel size has to be
301  stored in a fixed location somewhere.
302  */
303  try
304  {
305  carto::Object vs = obj->header().getProperty( "voxel_size" );
306  bordersVolume->header().setProperty( "voxel_size", vs );
307  }
308  catch( ... )
309  { // never mind.
310  }
311 
312  }
313  else
314  {
315  //=== FULL VOLUME ======================================================
316  localMsg( "=== ALLOCATED FULL VIEW" );
317  rVol = soma::Reader< carto::Volume<T> >( dsi );
318  newoptions = carto::Object::value( carto::PropertySet() );
319  newoptions->copyProperties( options );
320  rVol.setOptions( newoptions );
321  localMsg( "reading volume..." );
322  obj = rVol.read();
323  }
324 
325  return obj;
326  }
327 
328  template <typename T> carto::Volume<T>*
331  std::vector<int> position,
332  std::vector<int> frame,
333  std::vector<int> borders,
334  carto::Object options )
335  {
336  //=== VARIABLES ==========================================================
337  std::vector<int> viewframe( frame );
338  size_t dim, ndim = std::max( position.size(), frame.size() );
339  if( viewframe.size() < ndim )
340  viewframe.resize( ndim, 0 );
341  std::vector<int> viewpos( position );
342  if( viewpos.size() < ndim )
343  viewpos.resize( ndim, 0 );
344  std::vector<int> fullsize; // full size
345  std::vector<int> borderframe( ndim, 1 ); // allocated volume size
346  std::vector<int> borderpos; // allocated volume size
347  std::vector<int> readframe( ndim, 0 ); // read frame size
348  std::vector<int> readpos( ndim, 0 ); // read frame origin
349  carto::Object newoptions;
352  carto::VolumeRef<T> fullVolume, bordersVolume, readVolume;
353 // carto::Volume<T>* viewVolume;
354 
355  //=== UNALLOCATED FULL VOLUME ============================================
356  localMsg( "=== UNALLOCATED FULL VOLUME" );
357  rVol = soma::Reader<carto::Volume<T> >( dsi );
358  newoptions = carto::Object::value( carto::PropertySet() );
359  newoptions->setProperty( "unallocated", true );
360  newoptions->copyProperties( options );
361  rVol.setOptions( newoptions );
362  localMsg( "reading unallocated volume..." );
363  fullVolume = carto::VolumeRef<T>( rVol.read() );
364  localMsg( "reading size from volume..." );
365  fullsize = fullVolume->getSize();
366 // localMsg( "-> full size ( "
367 // + carto::toString( fullsize[0] ) + ", "
368 // + carto::toString( fullsize[1] ) + ", "
369 // + carto::toString( fullsize[2] ) + ", "
370 // + carto::toString( fullsize[3] ) + " )" );
371 // localMsg( "-> position ( "
372 // + carto::toString( position[0] ) + ", "
373 // + carto::toString( position[1] ) + ", "
374 // + carto::toString( position[2] ) + ", "
375 // + carto::toString( position[3] ) + " )" );
376 // localMsg( "-> borders ( "
377 // + carto::toString( borders[0] ) + ", "
378 // + carto::toString( borders[1] ) + ", "
379 // + carto::toString( borders[2] ) + ", "
380 // + carto::toString( borders[3] ) + " )" );
381  for( dim=0; dim<ndim; ++dim )
382  if( viewframe[ dim ] == 0
383  || viewframe[ dim ] + position[ dim ] > fullsize[ dim ] )
384  viewframe[ dim ] = (fullsize[ dim ] - position[ dim ]);
385  localMsg( "===" );
386 
387  if( borders[0] != 0 || borders[1] != 0 || borders[2] != 0 )
388  {
389  //=== ALLOCATED BORDERS VOLUME =========================================
390  localMsg( "=== ALLOCATED BORDERS VOLUME" );
391  localMsg( "computing borders..." );
392  // setting "bordersVolume" position / "fullVolume"
393  borderpos = viewpos;
394  borderpos[0] -= borders[0];
395  borderpos[1] -= borders[1];
396  borderpos[2] -= borders[2];
397  borderframe = viewframe;
398  borderframe[0] += 2*borders[0];
399  borderframe[1] += 2*borders[1];
400  borderframe[2] += 2*borders[2];
401  localMsg( "creating volume..." );
402  localMsg( "-> with frame size ( "
403  + carto::toString( borderframe[0] ) + ", "
404  + carto::toString( borderframe[1] ) + ", "
405  + carto::toString( borderframe[2] ) + ", "
406  + carto::toString( borderframe[3] ) + " )"
407  );
408  localMsg( "-> with frame pos ( "
409  + carto::toString( borderpos[0] ) + ", "
410  + carto::toString( borderpos[1] ) + ", "
411  + carto::toString( borderpos[2] ) + ", "
412  + carto::toString( borderpos[3] ) + " )"
413  );
414  bordersVolume = carto::VolumeRef<T>(
415  new carto::Volume<T>( fullVolume, borderpos, borderframe ) );
416 
417 // localMsg( "-> effective frame size ( "
418 // + carto::toString( bordersVolume->getSizeX() ) + ", "
419 // + carto::toString( bordersVolume->getSizeY() ) + ", "
420 // + carto::toString( bordersVolume->getSizeZ() ) + ", "
421 // + carto::toString( bordersVolume->getSizeT() ) + " )"
422 // );
423 
424  //=== UNALLOCATED READ VIEW ============================================
425  localMsg( "=== UNALLOCATED READ VIEW" );
426  localMsg( "computing read frame..." );
427  // setting "readVolume" position / "bordersVolume"
428  readpos[0] = ( borderpos[0] < 0 ? borders[0] : 0 );
429  readpos[1] = ( borderpos[1] < 0 ? borders[1] : 0 );
430  readpos[2] = ( borderpos[2] < 0 ? borders[2] : 0 );
431  readpos[3] = 0;
432  std::vector<int> borderdep( 3, 0 );
433  borderdep[0] = ( borderpos[0] + borderframe[0] - fullsize[0] > 0
434  ? borderpos[0] + borderframe[0] - fullsize[0] : 0 );
435  borderdep[1] = ( borderpos[1] + borderframe[1] - fullsize[1] > 0
436  ? borderpos[1] + borderframe[1] - fullsize[1] : 0 );
437  borderdep[2] = ( borderpos[2] + borderframe[2] - fullsize[2] > 0
438  ? borderpos[2] + borderframe[2] - fullsize[2] : 0 );
439  readframe[0] = borderframe[0] - readpos[0] - borderdep[0];
440  readframe[1] = borderframe[1] - readpos[1] - borderdep[1];
441  readframe[2] = borderframe[2] - readpos[2] - borderdep[2];
442  readframe[3] = borderframe[3];
443  rView = soma::Reader<carto::Volume<T> >( rVol.dataSourceInfo() );
444  newoptions = carto::Object::value( carto::PropertySet() );
445  newoptions->setProperty( "partial_reading", true );
446  newoptions->copyProperties( options );
447  rView.setOptions( newoptions );
448  localMsg( "creating volume..." );
449  localMsg( "-> with frame size ( "
450  + carto::toString( readframe[0] ) + ", "
451  + carto::toString( readframe[1] ) + ", "
452  + carto::toString( readframe[2] ) + ", "
453  + carto::toString( readframe[3] ) + " )"
454  );
455  localMsg( "-> with frame pos ( "
456  + carto::toString( readpos[0] ) + ", "
457  + carto::toString( readpos[1] ) + ", "
458  + carto::toString( readpos[2] ) + ", "
459  + carto::toString( readpos[3] ) + " )"
460  );
461  readVolume = carto::VolumeRef<T>(
462  new carto::Volume<T>( bordersVolume, readpos, readframe ) );
463 
464 // localMsg( "-> effective read view size ( "
465 // + carto::toString( readVolume->getSizeX() ) + ", "
466 // + carto::toString( readVolume->getSizeY() ) + ", "
467 // + carto::toString( readVolume->getSizeZ() ) + ", "
468 // + carto::toString( readVolume->getSizeT() ) + " )"
469 // );
470 
471  localMsg( "reading frame..." );
472  rView.read( *readVolume );
473 
474 // localMsg( "-> effective read view size after read ( "
475 // + carto::toString( readVolume->getSizeX() ) + ", "
476 // + carto::toString( readVolume->getSizeY() ) + ", "
477 // + carto::toString( readVolume->getSizeZ() ) + ", "
478 // + carto::toString( readVolume->getSizeT() ) + " )"
479 // );
480 
481  //=== UNALLOCATED PROCCESSED VOLUME ====================================
482  localMsg( "=== UNALLOCATED PROCESSED VOLUME" );
483  localMsg( "computing view frame..." );
484  // setting "viewVolume" position / "bordersVolume"
485  viewpos[0] = borders[0];
486  viewpos[1] = borders[1];
487  viewpos[2] = borders[2];
488  viewpos[3] = 0;
489  localMsg( "creating volume..." );
490  localMsg( "-> with frame size ( "
491  + carto::toString( viewframe[0] ) + ", "
492  + carto::toString( viewframe[1] ) + ", "
493  + carto::toString( viewframe[2] ) + ", "
494  + carto::toString( viewframe[3] ) + " )"
495  );
496  localMsg( "-> with frame pos ( "
497  + carto::toString( viewpos[0] ) + ", "
498  + carto::toString( viewpos[1] ) + ", "
499  + carto::toString( viewpos[2] ) + ", "
500  + carto::toString( viewpos[3] ) + " )"
501  );
502  if(obj)
503  *obj = carto::Volume<T>( bordersVolume, viewpos, viewframe );
504  else
505  obj = new carto::Volume<T>( bordersVolume, viewpos, viewframe );
506 
507  localMsg( "copying header..." );
508  obj->blockSignals( true );
509  obj->header().copyProperties( carto::Object::value( readVolume->header() ) );
510  /* copy voxel_size to underlying volume, if any.
511  This should probably be more general, but cannot be applied to all
512  header properties (size, transformations...).
513  WARNING: Moreover here we do not guarantee to keep both voxel_size
514  unique: we point to the same vector of values for now, but it can be
515  replaced (thus, duplicated) by a setProperty().
516  We could use a addBuiltinProperty(), but then the voxel size has to be
517  stored in a fixed location somewhere.
518  */
519  try
520  {
521  carto::Object vs = obj->header().getProperty( "voxel_size" );
522  bordersVolume->header().setProperty( "voxel_size", vs );
523  }
524  catch( ... )
525  { // never mind.
526  }
527  carto::PropertySet & ps = obj->header();
528  ps.setProperty( "sizeX", viewframe[0] );
529  ps.setProperty( "sizeY", viewframe[1] );
530  ps.setProperty( "sizeZ", viewframe[2] );
531  ps.setProperty( "sizeT", viewframe[3] );
532  ps.setProperty( "volume_dimension", viewframe );
533  obj->blockSignals( false );
534  }
535  else
536  {
537  //=== ALLOCATED PROCESSED VOLUME =======================================
538  localMsg( "=== ALLOCATED PROCESSED VOLUME" );
539  rView = soma::Reader<carto::Volume<T> >( rVol.dataSourceInfo() );
540  newoptions = carto::Object::value( carto::PropertySet() );
541  newoptions->setProperty( "partial_reading", true );
542  newoptions->copyProperties( options );
543  rView.setOptions( newoptions );
544  localMsg( "creating volume..." );
545  if( obj )
546  *obj = carto::Volume<T>( fullVolume, viewpos, viewframe );
547  else
548  obj = new carto::Volume<T>( fullVolume, viewpos, viewframe );
549 
550  localMsg( "reading partial volume..." );
551  rView.read( *obj );
552  }
553 
554  return obj;
555  }
556 
557 }
558 
559 #undef localMsg
560 #endif
N-D Volume main class.
T max(const Volume< T > &vol)
Returns the maximum value of the volume.
Definition: volumeutil.h:762
Convenient handle for a Volume - this is normally the entry point for all volumes handling...
const AllocatorContext & allocatorContext() const
returns volume&#39;s AllocatorContext
Definition: volumebase_d.h:595
static carto::Volume< T > * readFull(carto::Volume< T > *obj, carto::rc_ptr< DataSourceInfo > dsi, std::vector< int > borders, carto::Object options)
Worker for full reading case.
const PropertySet & header() const
const carto::rc_ptr< DataSourceInfo > & dataSourceInfo() const
void setProperty(const std::string &, const T &)
static carto::Volume< T > * readPartial(carto::Volume< T > *obj, carto::rc_ptr< DataSourceInfo > dsi, std::vector< int > position, std::vector< int > frame, std::vector< int > borders, carto::Object options)
Worker for partial reading case.
void setAllocatorContext(const AllocatorContext &ac)
static carto::Volume< T > * read(carto::Volume< T > *obj, carto::rc_ptr< DataSourceInfo > dsi, carto::Object options)
Manages all the volumes necessary and returns the final Volume.
#define localMsg(message)
DataSourceInfo check(DataSourceInfo dsi, carto::Object options=carto::none(), int passbegin=1, int passend=3)
std::vector< int > getSize() const
void setOptions(carto::Object options)
static Object value()
static std::set< std::string > listReadProperties()
list of properties triggering partial reading and/or borders
virtual bool read(T &obj, carto::Object header=carto::none(), int passbegin=1, int passend=4)
void blockSignals(bool)
const PropertySet & header() const
std::string toString(const T &object)
const carto::Object & header() const