aimsdata  5.1.2
Neuroimaging data handling
wavefrontmeshW.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 AIMS_IO_WAVEFRONTMESHW_H
35 #define AIMS_IO_WAVEFRONTMESHW_H
36 
38 #include <aims/io/defaultItemW.h>
39 #include <aims/data/pheader.h>
40 #include <aims/mesh/surface.h>
41 #include <aims/io/writer.h>
42 #include <aims/io/datatypecode.h>
46 
47 
48 namespace
49 {
50 
51  template <typename T>
52  inline
53  T _clamp( const T& value, float m )
54  {
55  T new_value;
56 
57  if( (float) value < m ) // clamp
58  new_value = (T) m;
59  else if( (float) value > 1. - m )
60  new_value = (T) ( 1. - m );
61  else
62  return value;
63 
64  return new_value;
65  }
66 
67 
68  template <>
69  inline
70  Void _clamp( const Void &, float )
71  {
72  return Void();
73  }
74 
75 
76  template <typename T>
77  class _printTextureCoord
78  {
79  public:
80  inline static
81  std::string p( const T & tex, float m = 0.001 )
82  {
83  std::stringstream s;
84  s << _clamp( tex, m ) << " 0"; // mut extend to 2D
85  return s.str();
86  }
87  };
88 
89 
90  template <typename T, int D>
91  class _printTextureCoord< AimsVector<T, D> >
92  {
93  public:
94  inline static
95  std::string p( const AimsVector<T, D> & tex, float m )
96  {
97  std::stringstream s;
98  for( int i=0; i<3 && i<D; ++i )
99  {
100  if( i != 0 )
101  s << " ";
102  s << _clamp( tex[i], m );
103  }
104  if( D == 1 )
105  s << " 0";
106  return s.str();
107  }
108  };
109 
110 }
111 
112 
113 namespace aims
114 {
115 
116  template<int D, class T>
118  {
119  public:
120  WavefrontMeshWriter( const std::string & name )
121  : _name( name ) { }
123 
124  inline void write( const AimsTimeSurface<D,T> & thing,
125  carto::Object options = carto::none() );
126 
128  inline static std::string removeExtension( const std::string& name );
129 
130  private:
131  inline static PythonHeader* writeHeader(
132  const Header & header, std::ostream & os, const std::string & filename,
133  const std::string & dtype, carto::Object options );
134  inline static void writeObjectHeader( std::ostream & os, int timestep,
135  PythonHeader *hdr,
136  const std::string & obj_filename,
137  carto::Object options );
138  inline static void writeMtl( PythonHeader *hdr, carto::Object options );
139  std::string _name;
140  };
141 
142 
143  template<int D>
145  {
146  public:
147  WavefrontMeshWriter( const std::string & name )
148  : _name( name ) { }
150 
151  inline void write( const AimsTimeSurface<D, Void> & thing,
152  carto::Object options = carto::none() );
153 
154  private:
155  template <int U, typename T>
157 
159  inline static std::string removeExtension(const std::string& name);
160 
161  inline static PythonHeader* writeHeader(
162  const Header & header, std::ostream & os, const std::string & filename,
163  const std::string & dtype, carto::Object options );
164  inline static void writeObjectHeader(
165  std::ostream & os, int timestep, PythonHeader *hdr,
166  const std::string & obj_filename, carto::Object options );
167  inline static void writeMtl( PythonHeader *hdr, carto::Object options );
168 
169  private:
170  std::string _name;
171  };
172 
173 
174  template <int D, class T>
175  inline
178  const AimsTimeSurface<D,T> & thing )
179  {
180  writer.write( thing );
181  return( writer );
182  }
183 
184 
185  template <int D, class T> inline
187  const std::string& name )
188  {
190  }
191 
192 
193  template <int D, class T> inline
195  const Header & header, std::ostream & os, const std::string & filename,
196  const std::string & dtype, carto::Object options )
197  {
198  return WavefrontMeshWriter<D, Void>::writeHeader( header, os, filename,
199  dtype, options );
200  }
201 
202 
203  template <int D, class T> inline
204  void WavefrontMeshWriter<D,T>::writeObjectHeader(
205  std::ostream & os, int timestep,
206  PythonHeader *hdr, const std::string & obj_filename,
207  carto::Object options )
208  {
209  WavefrontMeshWriter<D, Void>::writeObjectHeader( os, timestep, hdr,
210  obj_filename, options );
211  }
212 
213 
214  template <int D, class T> inline
215  void WavefrontMeshWriter<D,T>::writeMtl( PythonHeader *hdr,
216  carto::Object options )
217  {
218  WavefrontMeshWriter<D, Void>::writeMtl( hdr, options );
219  }
220 
221  // ---
222 
223  template <int D> inline
225  const std::string& name )
226  {
227  std::string res = name;
228  std::string ext="";
229  if( res.length() > 4 )
230  ext = res.substr( int(res.length() - 4), 4 );
231  if( ext == ".obj" )
232  res = res.substr( 0, res.length() - 4 );
233  return res;
234  }
235 
236 
237  template <int D>
238  PythonHeader* WavefrontMeshWriter<D, Void>::writeHeader(
239  const Header & header, std::ostream & os, const std::string & filename,
240  const std::string & dtype, carto::Object /* options */ )
241  {
242  PythonHeader *hdr = new PythonHeader;
243  const PythonHeader
244  *ph = dynamic_cast<const PythonHeader *>( &header );
245  if( ph )
246  hdr->copy( *ph );
247 
248  if( hdr->hasProperty( "nb_t_pos" ) )
249  hdr->removeProperty( "nb_t_pos" );
250  hdr->setProperty( "file_type", std::string( "WAVEFRONT" ) );
251  hdr->setProperty( "object_type",
253  AimsTimeSurface<D, Void> >::objectType() );
254  if( !dtype.empty() )
255  hdr->setProperty( "data_type", dtype );
256 
257  os << "# Wavefront OBJ\n" << std::endl;
258 
259  carto::Object material;
260  try
261  {
262  material = hdr->getProperty( "material" );
263  if( material.get() )
264  {
265  std::string mtlfilename = removeExtension( filename ) + ".mtl";
266  os << "mtllib " << carto::FileUtil::basename( mtlfilename )
267  << std::endl << std::endl;
268 
269  hdr->setProperty( "mtl", carto::Dictionary() );
270  carto::Object mtl = hdr->getProperty( "mtl" );
271  mtl->setProperty( "filename", mtlfilename );
272  }
273  }
274  catch( ... )
275  {
276  }
277 
278  return hdr;
279  }
280 
281 
282  template <int D>
283  void WavefrontMeshWriter<D, Void>::writeObjectHeader(
284  std::ostream & os, int timestep, PythonHeader *hdr,
285  const std::string & obj_filename, carto::Object /* options */ )
286  {
287  std::stringstream namess;
289  obj_filename ) ) << "_" << timestep;
290  std::string name = namess.str();
291  os << "o " << name << std::endl << std::endl;
292  os << "s 1\n" << std::endl;
293 
294  if( hdr->hasProperty( "material" ) )
295  {
296  carto::Object material, mtl;
297  material = hdr->getProperty( "material" );
298  mtl = hdr->getProperty( "mtl" );
299 
300  os << "usemtl " << name << std::endl << std::endl;
301 
303 
304  try
305  {
306  mtldict = mtl->getProperty( name );
307  }
308  catch( ... )
309  {
310  mtl->setProperty( name, mtldict );
311  }
312 
313  try
314  {
315  carto::Object ambient = material->getProperty( "ambient" );
316  carto::Object it = ambient->objectIterator();
317  std::stringstream s;
318  for( int i=0; it->isValid() && i < 3; it->next(), ++i )
319  {
320  if( i != 0 )
321  s << " ";
322  s << it->currentValue()->getScalar();
323  }
324  mtldict->setProperty( "Ka", s.str() );
325  }
326  catch( ... )
327  {
328  }
329 
330  try
331  {
332  carto::Object diffuse = material->getProperty( "diffuse" );
333  carto::Object it = diffuse->objectIterator();
334  std::stringstream s;
335  int i;
336  for( i=0; it->isValid() && i < 3; it->next(), ++i )
337  {
338  if( i != 0 )
339  s << " ";
340  s << it->currentValue()->getScalar();
341  }
342  mtldict->setProperty( "Kd", s.str() );
343  if( i == 3 && it->isValid() )
344  {
345  std::stringstream sd;
346  sd << it->currentValue()->getScalar();
347  mtldict->setProperty( "d", sd.str() );
348  }
349  }
350  catch( ... )
351  {
352  }
353 
354  try
355  {
356  carto::Object specular = material->getProperty( "specular" );
357  carto::Object it = specular->objectIterator();
358  std::stringstream s;
359  for( int i=0; it->isValid() && i < 3; it->next(), ++i )
360  {
361  if( i != 0 )
362  s << " ";
363  s << it->currentValue()->getScalar();
364  }
365  mtldict->setProperty( "Ks", s.str() );
366  }
367  catch( ... )
368  {
369  }
370 
371  try
372  {
373  carto::Object shininess = material->getProperty( "shininess" );
374  std::stringstream s;
375  s << shininess->getScalar();
376  mtldict->setProperty( "Ns", s.str() );
377  }
378  catch( ... )
379  {
380  }
381 
382  }
383 
384  if( hdr->hasProperty( "_texture_palettes" ) )
385  {
386  std::map<int, carto::Object> palettes;
387  hdr->getProperty( "_texture_palettes", palettes );
388  std::map<int, carto::Object>::iterator ip = palettes.find( timestep );
389  if( ip != palettes.end() )
390  {
391  std::string pal_fname = name + ".png";
392 
393  carto::Object mtl = hdr->getProperty( "mtl" );
395 
396  try
397  {
398  mtldict = mtl->getProperty( name );
399  }
400  catch( ... )
401  {
402  mtl->setProperty( name, mtldict );
403  }
404 
405  // texture space offsets / scaling.
406  // WARNING: blender doesn't support texture map options.
407  std::stringstream mapkd_val_s;
408  std::vector<float> texoffset;
409  if( hdr->getProperty( "texture_offset", texoffset )
410  && texoffset.size() == 3 )
411  {
412  mapkd_val_s << "-o " << texoffset[0] << " " << texoffset[1] << " "
413  << texoffset[2] << " ";
414  }
415  std::vector<float> texscale;
416  if( hdr->getProperty( "texture_scale", texscale )
417  && texscale.size() == 3 )
418  {
419  mapkd_val_s << "-s " << texscale[0] << " " << texscale[1] << " "
420  << texscale[2] << " ";
421  }
422  mtldict->setProperty( "map_Kd", mapkd_val_s.str() + pal_fname );
423  pal_fname = carto::FileUtil::dirname( obj_filename ) +
424  carto::FileUtil::separator() + pal_fname;
425  Writer<carto::Volume<AimsRGBA> > w( pal_fname );
426  w.write(
427  ip->second->value<carto::rc_ptr<carto::Volume<AimsRGBA> > >() );
428  }
429  }
430  }
431 
432 
433  template <int D>
434  void WavefrontMeshWriter<D, Void>::writeMtl( PythonHeader *hdr,
435  carto::Object /* options */ )
436  {
437  carto::Object mtl;
438  try
439  {
440  mtl = hdr->getProperty( "mtl" );
441  }
442  catch( ... )
443  {
444  return;
445  }
446 
447  std::string mtlfilename = mtl->getProperty( "filename" )->getString();
448  std::ofstream ms( mtlfilename.c_str() );
449  carto::Object oit = mtl->objectIterator();
450  for( ; oit->isValid(); oit->next() )
451  {
452  if( oit->key() == "filename" )
453  continue;
454  std::string oname = oit->key();
455  ms << "newmtl " << oname << std::endl << std::endl;
456  carto::Object it = oit->currentValue()->objectIterator();
457  for( ; it->isValid(); it->next() )
458  {
459  ms << it->key() << " " << it->currentValue()->getString() << std::endl;
460  }
461  }
462  hdr->removeProperty( "mtl" );
463  }
464 
465  // ---
466 
467  template <int D, class T>
469  carto::Object options )
470  {
471  std::string fname = _name;
472  std::ofstream os( fname.c_str() );
473  if( !os )
474  throw carto::file_error( fname );
475 
476  PythonHeader *hdr = writeHeader(
477  thing.header(), os, _name,
478  carto::DataTypeCode< AimsTimeSurface<D, T> >::dataType(), options );
479 
480  typename AimsTimeSurface<D,T>::const_iterator is, es = thing.end();
481  int timestep = 0;
482 
483  for( is=thing.begin(); is!=es; ++is, ++timestep )
484  {
485  writeObjectHeader( os, timestep, hdr, fname, options );
486 
487  const std::vector<Point3df> &vert = (*is).second.vertex();
488  const std::vector<Point3df> &norm = (*is).second.normal();
489  const std::vector<AimsVector<uint,D> > &poly= is->second.polygon();
490 
491  // vertices
492  for( std::vector<Point3df>::const_iterator iv = vert.begin();
493  iv != vert.end(); ++iv )
494  os << "v " << (*iv)[0] << " " << (*iv)[1] << " " << (*iv)[2]
495  << std::endl;
496  os << std::endl;
497 
498  // normals
499  for( std::vector<Point3df>::const_iterator in = norm.begin();
500  in != norm.end(); ++in )
501  os << "vn " << (*in)[0] << " " << (*in)[1] << " " << (*in)[2]
502  << std::endl;
503  os << std::endl;
504 
505  // texture
506  typename std::vector<T>::const_iterator it,
507  et=is->second.texture().end();
508 
509  float m = 1. / 512; // minimum value to clamp, for a 256 size texture
510  /* need to clamp is maybe just due to blender ?
511  Apparently texture coord values of 0 and 1 are "outside" the texture
512  (rendered as a strange pink color (?))
513  */
514 
515  for( it=is->second.texture().begin(); it!=et; ++it )
516  {
517  os << "vt " << _printTextureCoord<T>::p( *it, m ) << std::endl;
518  }
519  os << std::endl;
520 
521  // polygons
522  for( typename std::vector<AimsVector<uint,D> >::const_iterator ip =
523  poly.begin(); ip != poly.end(); ++ip )
524  {
525  if( D == 2 )
526  os << "l";
527  else
528  os << "f";
529  for( int p=0; p<D; ++p )
530  // WARNING obj indices start at 1 (like matlab...)
531  os << " " << (*ip)[p] + 1 << "/" << (*ip)[p] + 1 << "/"
532  << (*ip)[p] + 1;
533  os << std::endl;
534  }
535  os << std::endl;
536 
537  }
538 
539  writeMtl( hdr, options );
540  hdr->writeMinf( fname + ".minf" );
541 
542  }
543 
544 
545 
546  template <int D>
548  const AimsTimeSurface<D, Void> & thing, carto::Object options )
549  {
550  std::string fname = _name;
551  std::ofstream os( fname.c_str() );
552  if( !os )
553  throw carto::file_error( fname );
554 
555  PythonHeader *hdr = writeHeader( thing.header(), os, _name, "VOID",
556  options );
557 
558  typename AimsTimeSurface<D, Void>::const_iterator is, es = thing.end();
559  int timestep = 0;
560 
561  for( is=thing.begin(); is!=es; ++is, ++timestep )
562  {
563  writeObjectHeader( os, timestep, hdr, fname, options );
564 
565  const std::vector<Point3df> &vert = (*is).second.vertex();
566  const std::vector<Point3df> &norm = (*is).second.normal();
567  const std::vector<AimsVector<uint,D> > &poly= is->second.polygon();
568 
569  // vertices
570  for( std::vector<Point3df>::const_iterator iv = vert.begin();
571  iv != vert.end(); ++iv )
572  os << "v " << (*iv)[0] << " " << (*iv)[1] << " " << (*iv)[2]
573  << std::endl;
574  os << std::endl;
575 
576  // normals
577  for( std::vector<Point3df>::const_iterator in = norm.begin();
578  in != norm.end(); ++in )
579  os << "vn " << (*in)[0] << " " << (*in)[1] << " " << (*in)[2]
580  << std::endl;
581  os << std::endl;
582 
583  // polygons
584  for( typename std::vector<AimsVector<uint,D> >::const_iterator ip =
585  poly.begin(); ip != poly.end(); ++ip )
586  {
587  if( D == 2 )
588  os << "l";
589  else
590  os << "f";
591  for( int p=0; p<D; ++p )
592  // WARNING obj indices start at 1 (like matlab...)
593  os << " " << (*ip)[p] + 1 << "//" << (*ip)[p] + 1;
594  os << std::endl;
595  }
596  os << std::endl;
597 
598  }
599 
600  writeMtl( hdr, options );
601  hdr->writeMinf( fname + ".minf" );
602  }
603 }
604 
605 
606 #endif
The template class to manage a mesh with time if needed.
Definition: surface.h:317
const std::vector< AimsVector< uint, D > > & polygon() const
Get a const reference to the vector of polygons of the 0 surface.
Definition: surface.h:362
const std::vector< T > & texture() const
Get a const reference to the vector of textures of the 0 surface.
Definition: surface.h:356
const aims::PythonHeader & header() const
Get the header.
Definition: surface.h:328
std::map< int, AimsSurface< D, T > >::const_iterator const_iterator
Definition: surface.h:321
iterator begin()
Attributed python-like header, stores all needed information about an object, currently used for volu...
Definition: pheader.h:52
virtual bool writeMinf(const std::string &filename)
write meta-info header, non-const version (may change some attributes)
WavefrontMeshWriter(const std::string &name)
void write(const AimsTimeSurface< D, T > &thing, carto::Object options=carto::none())
static std::string removeExtension(const std::string &name)
Return a name without .obj extension.
WavefrontMeshWriter(const std::string &name)
static char separator()
static std::string dirname(const std::string &)
static std::string basename(const std::string &)
static std::string removeExtension(const std::string &)
static Object value()
GenericObject * get() const
The class for EcatSino data write operation.
Definition: borderfiller.h:13
MotionWriter & operator<<(MotionWriter &writer, const AffineTransformation3d &thing) __attribute__((__deprecated__("OBSOLETE")))
— OBSOLETE —
Definition: motionW.h:87
std::map< std::string, Object > Dictionary
Object none()
AIMSDATA_API float norm(const Tensor &thing)
Definition: tensor.h:141