aimsdata 6.0.0
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
39#include <aims/data/pheader.h>
40#include <aims/mesh/surface.h>
41#include <aims/io/writer.h>
43#include <cartodata/volume/volume.h>
44#include <cartobase/exception/file.h>
45#include <cartobase/stream/fileutil.h>
46
47
48namespace
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
113namespace 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
194 PythonHeader* WavefrontMeshWriter<D,T>::writeHeader(
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",
252 carto::DataTypeCode<
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
302 carto::Object mtldict = carto::Object::value( carto::Dictionary() );
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" );
394 carto::Object mtldict = carto::Object::value( carto::Dictionary() );
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 aims::PythonHeader & header() const
Get the header.
Definition surface.h:332
std::map< int, AimsSurface< D, T > >::const_iterator const_iterator
Definition surface.h:321
Attributed python-like header, stores all needed information about an object, currently used for volu...
Definition pheader.h:52
virtual void copy(const PythonHeader &, bool keepUuid=false)
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)
Generic writer for every format of Aims object.
Definition writer.h:94
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()
T * get() const
The class for EcatSino data write operation.
AIMSDATA_API PovWriter< D, T > & operator<<(PovWriter< D, T > &writer, const AimsTimeSurface< D, T > &thing)
Definition povW.h:72
std::map< std::string, Object > Dictionary
Object none()
float norm(const AimsVector< T, D > &v1)