aimsdata 6.0.13
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 emission = material->getProperty( "emission" );
357 carto::Object it = emission->objectIterator();
358 std::stringstream s;
359 int i;
360 for( i=0; it->isValid() && i < 3; it->next(), ++i )
361 {
362 if( i != 0 )
363 s << " ";
364 s << it->currentValue()->getScalar();
365 }
366 mtldict->setProperty( "Ke", s.str() );
367 }
368 catch( ... )
369 {
370 }
371
372 try
373 {
374 carto::Object specular = material->getProperty( "specular" );
375 carto::Object it = specular->objectIterator();
376 std::stringstream s;
377 for( int i=0; it->isValid() && i < 3; it->next(), ++i )
378 {
379 if( i != 0 )
380 s << " ";
381 s << it->currentValue()->getScalar();
382 }
383 mtldict->setProperty( "Ks", s.str() );
384 }
385 catch( ... )
386 {
387 }
388
389 try
390 {
391 carto::Object shininess = material->getProperty( "shininess" );
392 std::stringstream s;
393 s << shininess->getScalar();
394 mtldict->setProperty( "Ns", s.str() );
395 }
396 catch( ... )
397 {
398 }
399
400 }
401
402 if( hdr->hasProperty( "_texture_palettes" ) )
403 {
404 std::map<int, carto::Object> palettes;
405 hdr->getProperty( "_texture_palettes", palettes );
406 std::map<int, carto::Object>::iterator ip = palettes.find( timestep );
407 if( ip != palettes.end() )
408 {
409 std::string pal_fname = name + ".png";
410
411 carto::Object mtl = hdr->getProperty( "mtl" );
412 carto::Object mtldict = carto::Object::value( carto::Dictionary() );
413
414 try
415 {
416 mtldict = mtl->getProperty( name );
417 }
418 catch( ... )
419 {
420 mtl->setProperty( name, mtldict );
421 }
422
423 // texture space offsets / scaling.
424 // WARNING: blender doesn't support texture map options.
425 std::stringstream mapkd_val_s;
426 std::vector<float> texoffset;
427 if( hdr->getProperty( "texture_offset", texoffset )
428 && texoffset.size() == 3 )
429 {
430 mapkd_val_s << "-o " << texoffset[0] << " " << texoffset[1] << " "
431 << texoffset[2] << " ";
432 }
433 std::vector<float> texscale;
434 if( hdr->getProperty( "texture_scale", texscale )
435 && texscale.size() == 3 )
436 {
437 mapkd_val_s << "-s " << texscale[0] << " " << texscale[1] << " "
438 << texscale[2] << " ";
439 }
440 mtldict->setProperty( "map_Kd", mapkd_val_s.str() + pal_fname );
441 pal_fname = carto::FileUtil::dirname( obj_filename ) +
442 carto::FileUtil::separator() + pal_fname;
443 Writer<carto::Volume<AimsRGBA> > w( pal_fname );
444 w.write(
445 ip->second->value<carto::rc_ptr<carto::Volume<AimsRGBA> > >() );
446 }
447 }
448 }
449
450
451 template <int D>
452 void WavefrontMeshWriter<D, Void>::writeMtl( PythonHeader *hdr,
453 carto::Object /* options */ )
454 {
455 carto::Object mtl;
456 try
457 {
458 mtl = hdr->getProperty( "mtl" );
459 }
460 catch( ... )
461 {
462 return;
463 }
464
465 std::string mtlfilename = mtl->getProperty( "filename" )->getString();
466 std::ofstream ms( mtlfilename.c_str() );
467 carto::Object oit = mtl->objectIterator();
468 for( ; oit->isValid(); oit->next() )
469 {
470 if( oit->key() == "filename" )
471 continue;
472 std::string oname = oit->key();
473 ms << "newmtl " << oname << std::endl << std::endl;
474 carto::Object it = oit->currentValue()->objectIterator();
475 for( ; it->isValid(); it->next() )
476 {
477 ms << it->key() << " " << it->currentValue()->getString() << std::endl;
478 }
479 }
480 hdr->removeProperty( "mtl" );
481 }
482
483 // ---
484
485 template <int D, class T>
487 carto::Object options )
488 {
489 std::string fname = _name;
490 std::ofstream os( fname.c_str() );
491 if( !os )
492 throw carto::file_error( fname );
493
494 PythonHeader *hdr = writeHeader(
495 thing.header(), os, _name,
496 carto::DataTypeCode< AimsTimeSurface<D, T> >::dataType(), options );
497
498 typename AimsTimeSurface<D,T>::const_iterator is, es = thing.end();
499 int timestep = 0;
500
501 for( is=thing.begin(); is!=es; ++is, ++timestep )
502 {
503 writeObjectHeader( os, timestep, hdr, fname, options );
504
505 const std::vector<Point3df> &vert = (*is).second.vertex();
506 const std::vector<Point3df> &norm = (*is).second.normal();
507 const std::vector<AimsVector<uint,D> > &poly= is->second.polygon();
508
509 // vertices
510 for( std::vector<Point3df>::const_iterator iv = vert.begin();
511 iv != vert.end(); ++iv )
512 os << "v " << (*iv)[0] << " " << (*iv)[1] << " " << (*iv)[2]
513 << std::endl;
514 os << std::endl;
515
516 // normals
517 for( std::vector<Point3df>::const_iterator in = norm.begin();
518 in != norm.end(); ++in )
519 os << "vn " << (*in)[0] << " " << (*in)[1] << " " << (*in)[2]
520 << std::endl;
521 os << std::endl;
522
523 // texture
524 typename std::vector<T>::const_iterator it,
525 et=is->second.texture().end();
526
527 float m = 1. / 512; // minimum value to clamp, for a 256 size texture
528 /* need to clamp is maybe just due to blender ?
529 Apparently texture coord values of 0 and 1 are "outside" the texture
530 (rendered as a strange pink color (?))
531 */
532
533 for( it=is->second.texture().begin(); it!=et; ++it )
534 {
535 os << "vt " << _printTextureCoord<T>::p( *it, m ) << std::endl;
536 }
537 os << std::endl;
538
539 // polygons
540 for( typename std::vector<AimsVector<uint,D> >::const_iterator ip =
541 poly.begin(); ip != poly.end(); ++ip )
542 {
543 if( D == 2 )
544 os << "l";
545 else
546 os << "f";
547 for( int p=0; p<D; ++p )
548 // WARNING obj indices start at 1 (like matlab...)
549 os << " " << (*ip)[p] + 1 << "/" << (*ip)[p] + 1 << "/"
550 << (*ip)[p] + 1;
551 os << std::endl;
552 }
553 os << std::endl;
554
555 }
556
557 writeMtl( hdr, options );
558 hdr->writeMinf( fname + ".minf" );
559
560 }
561
562
563
564 template <int D>
566 const AimsTimeSurface<D, Void> & thing, carto::Object options )
567 {
568 std::string fname = _name;
569 std::ofstream os( fname.c_str() );
570 if( !os )
571 throw carto::file_error( fname );
572
573 PythonHeader *hdr = writeHeader( thing.header(), os, _name, "VOID",
574 options );
575
576 typename AimsTimeSurface<D, Void>::const_iterator is, es = thing.end();
577 int timestep = 0;
578
579 for( is=thing.begin(); is!=es; ++is, ++timestep )
580 {
581 writeObjectHeader( os, timestep, hdr, fname, options );
582
583 const std::vector<Point3df> &vert = (*is).second.vertex();
584 const std::vector<Point3df> &norm = (*is).second.normal();
585 const std::vector<AimsVector<uint,D> > &poly= is->second.polygon();
586
587 // vertices
588 for( std::vector<Point3df>::const_iterator iv = vert.begin();
589 iv != vert.end(); ++iv )
590 os << "v " << (*iv)[0] << " " << (*iv)[1] << " " << (*iv)[2]
591 << std::endl;
592 os << std::endl;
593
594 // normals
595 for( std::vector<Point3df>::const_iterator in = norm.begin();
596 in != norm.end(); ++in )
597 os << "vn " << (*in)[0] << " " << (*in)[1] << " " << (*in)[2]
598 << std::endl;
599 os << std::endl;
600
601 // polygons
602 for( typename std::vector<AimsVector<uint,D> >::const_iterator ip =
603 poly.begin(); ip != poly.end(); ++ip )
604 {
605 if( D == 2 )
606 os << "l";
607 else
608 os << "f";
609 for( int p=0; p<D; ++p )
610 // WARNING obj indices start at 1 (like matlab...)
611 os << " " << (*ip)[p] + 1 << "//" << (*ip)[p] + 1;
612 os << std::endl;
613 }
614 os << std::endl;
615
616 }
617
618 writeMtl( hdr, options );
619 hdr->writeMinf( fname + ".minf" );
620 }
621}
622
623
624#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)