mirror of
https://github.com/CloudCompare/PoissonRecon.git
synced 2026-08-30 00:50:28 +08:00
538 lines
20 KiB
C++
538 lines
20 KiB
C++
/*
|
|
|
|
Header for PLY polygon files.
|
|
|
|
- Greg Turk, March 1994
|
|
|
|
A PLY file contains a single polygonal _object_.
|
|
|
|
An object is composed of lists of _elements_. Typical elements are
|
|
vertices, faces, edges and materials.
|
|
|
|
Each type of element for a given object has one or more _properties_
|
|
associated with the element type. For instance, a vertex element may
|
|
have as properties three floating-point values x,y,z and three unsigned
|
|
chars for red, green and blue.
|
|
|
|
---------------------------------------------------------------
|
|
|
|
Copyright (c) 1994 The Board of Trustees of The Leland Stanford
|
|
Junior University. All rights reserved.
|
|
|
|
Permission to use, copy, modify and distribute this software and its
|
|
documentation for any purpose is hereby granted without fee, provided
|
|
that the above copyright notice and this permission notice appear in
|
|
all copies of this software and that you do not sell the software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
|
WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
*/
|
|
|
|
|
|
#ifndef __PLY_H__
|
|
#define __PLY_H__
|
|
|
|
#include <vector>
|
|
#include "PlyFile.h"
|
|
#include "Geometry.h"
|
|
|
|
template< class Real > int PLYType( void );
|
|
template<> inline int PLYType< int >( void ){ return PLY_INT ; }
|
|
template<> inline int PLYType< char >( void ){ return PLY_CHAR ; }
|
|
template<> inline int PLYType< unsigned char >( void ){ return PLY_UCHAR ; }
|
|
template<> inline int PLYType< float >( void ){ return PLY_FLOAT ; }
|
|
template<> inline int PLYType< double >( void ){ return PLY_DOUBLE; }
|
|
template< class Real > inline int PLYType( void ){ fprintf( stderr , "[ERROR] Unrecognized type\n" ) , exit( 0 ); }
|
|
|
|
typedef struct PlyFace
|
|
{
|
|
unsigned char nr_vertices;
|
|
int *vertices;
|
|
int segment;
|
|
} PlyFace;
|
|
static PlyProperty face_props[] =
|
|
{
|
|
PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( PlyFace , vertices ) , 1 , PLY_UCHAR, PLY_UCHAR , offsetof( PlyFace , nr_vertices ) ) ,
|
|
};
|
|
|
|
|
|
struct RGBColor
|
|
{
|
|
unsigned char c[3];
|
|
unsigned char& operator[]( int idx ) { return c[idx]; }
|
|
unsigned char operator[]( int idx ) const { return c[idx]; }
|
|
RGBColor( void ){ c[0] = c[1] = c[2] = 0; }
|
|
RGBColor( const RGBColor& rgb ){ memcpy( c , rgb.c , sizeof(unsigned char) * 3 ); }
|
|
RGBColor& operator = ( const RGBColor& rgb ){ memcpy( c , rgb.c , sizeof(unsigned char) * 3 ) ; return *this; }
|
|
};
|
|
///////////////
|
|
// PlyVertex //
|
|
///////////////
|
|
template< typename _Real , int Dim , typename _RealOnDisk=float >
|
|
class PlyVertex
|
|
{
|
|
public:
|
|
typedef _Real Real;
|
|
|
|
PlyVertex& operator += ( const PlyVertex& p ){ point += p.point ; return *this; }
|
|
PlyVertex& operator -= ( const PlyVertex& p ){ point -= p.point ; return *this; }
|
|
PlyVertex& operator *= ( Real s ) { point *= s ; return *this; }
|
|
PlyVertex& operator /= ( Real s ) { point /= s ; return *this; }
|
|
PlyVertex operator + ( const PlyVertex& p ) const { return PlyVertex( point + p.point ); }
|
|
PlyVertex operator - ( const PlyVertex& p ) const { return PlyVertex( point - p.point ); }
|
|
PlyVertex operator * ( Real s ) const { return PlyVertex( point * s ); }
|
|
PlyVertex operator / ( Real s ) const { return PlyVertex( point / s ); }
|
|
|
|
const static int PlyReadNum = Dim;
|
|
const static int PlyWriteNum = Dim;
|
|
|
|
static const PlyProperty* PlyReadProperties( void ){ return _PlyProperties; }
|
|
static const PlyProperty* PlyWriteProperties( void ){ return _PlyProperties; }
|
|
|
|
Point< Real , Dim > point;
|
|
PlyVertex( void ) {}
|
|
PlyVertex( Point< Real , Dim > p ) : point(p) { }
|
|
|
|
struct Transform
|
|
{
|
|
Transform( void ){}
|
|
Transform( const XForm< Real , Dim+1 >& xForm ) : _pointXForm(xForm) { }
|
|
PlyVertex operator() ( const PlyVertex& p ) const
|
|
{
|
|
PlyVertex _p;
|
|
_p.point = _pointXForm * p.point;
|
|
return _p;
|
|
}
|
|
protected:
|
|
XForm< Real , Dim+1 > _pointXForm;
|
|
};
|
|
|
|
protected:
|
|
static const PlyProperty _PlyProperties[];
|
|
};
|
|
|
|
template<>
|
|
const PlyProperty PlyVertex< float , 2 , float >::_PlyProperties[] =
|
|
{
|
|
PlyProperty( "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
};
|
|
template<>
|
|
const PlyProperty PlyVertex< double , 2 , float >::_PlyProperties[] =
|
|
{
|
|
PlyProperty( "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
};
|
|
template<>
|
|
const PlyProperty PlyVertex< float , 2 , double >::_PlyProperties[] =
|
|
{
|
|
PlyProperty( "x" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "y" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
};
|
|
template<>
|
|
const PlyProperty PlyVertex< double , 2 , double >::_PlyProperties[] =
|
|
{
|
|
PlyProperty( "x" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "y" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
};
|
|
|
|
template<>
|
|
const PlyProperty PlyVertex< float , 3 , float >::_PlyProperties[] =
|
|
{
|
|
PlyProperty( "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "z" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
};
|
|
template<>
|
|
const PlyProperty PlyVertex< double , 3 , float >::_PlyProperties[] =
|
|
{
|
|
PlyProperty( "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "z" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
};
|
|
template<>
|
|
const PlyProperty PlyVertex< float , 3 , double >::_PlyProperties[] =
|
|
{
|
|
PlyProperty( "x" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "y" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "z" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
};
|
|
template<>
|
|
const PlyProperty PlyVertex< double , 3 , double >::_PlyProperties[] =
|
|
{
|
|
PlyProperty( "x" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "y" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
PlyProperty( "z" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 ) ,
|
|
};
|
|
|
|
///////////////////////
|
|
// PlyVertexWithData //
|
|
///////////////////////
|
|
template< typename _Real , int Dim , typename Data , typename _RealOnDisk=float >
|
|
class PlyVertexWithData
|
|
{
|
|
public:
|
|
typedef _Real Real;
|
|
|
|
PlyVertexWithData& operator += ( const PlyVertexWithData& p ){ point += p.point , data += p.data ; return *this; }
|
|
PlyVertexWithData& operator -= ( const PlyVertexWithData& p ){ point -= p.point , data -= p.data ; return *this; }
|
|
PlyVertexWithData& operator *= ( Real s ) { point *= s , data *= s ; return *this; }
|
|
PlyVertexWithData& operator /= ( Real s ) { point /= s , data /= s ; return *this; }
|
|
PlyVertexWithData operator + ( const PlyVertexWithData& p ) const { return PlyVertexWithData( point + p.point , data + p.data ); }
|
|
PlyVertexWithData operator - ( const PlyVertexWithData& p ) const { return PlyVertexWithData( point - p.point , data - p.data ); }
|
|
PlyVertexWithData operator * ( Real s ) const { return PlyVertexWithData( point * s , data * s ); }
|
|
PlyVertexWithData operator / ( Real s ) const { return PlyVertexWithData( point / s , data / s ); }
|
|
|
|
const static int PlyReadNum = Data::PlyReadNum + Dim;
|
|
const static int PlyWriteNum = Data::PlyWriteNum + Dim;
|
|
|
|
static const PlyProperty* PlyReadProperties( void ){ _SetReadProperties() ; return _PlyReadProperties; }
|
|
static const PlyProperty* PlyWriteProperties( void ){ _SetWriteProperties() ; return _PlyWriteProperties; }
|
|
|
|
|
|
Point< Real , Dim > point;
|
|
Data data;
|
|
PlyVertexWithData( void ) {}
|
|
PlyVertexWithData( Point< Real , Dim > p , Data d ) : point(p) , data(d) { }
|
|
|
|
struct Transform
|
|
{
|
|
Transform( void ){}
|
|
Transform( const XForm< Real , Dim+1 >& xForm ) : _pointXForm(xForm) , _dataXForm(xForm) { }
|
|
PlyVertexWithData operator() ( const PlyVertexWithData& p ) const
|
|
{
|
|
PlyVertexWithData _p;
|
|
_p.point = _pointXForm * p.point;
|
|
_p.data = _dataXForm( p.data );
|
|
return _p;
|
|
}
|
|
protected:
|
|
XForm< Real , Dim+1 > _pointXForm;
|
|
typename Data::Transform _dataXForm;
|
|
};
|
|
|
|
protected:
|
|
static void _SetReadProperties( void );
|
|
static void _SetWriteProperties( void );
|
|
static PlyProperty _PlyReadProperties[];
|
|
static PlyProperty _PlyWriteProperties[];
|
|
};
|
|
template< typename Real , int Dim , typename Data , typename RealOnDisk > PlyProperty PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_PlyReadProperties[ PlyReadNum ];
|
|
template< typename Real , int Dim , typename Data , typename RealOnDisk > PlyProperty PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_PlyWriteProperties[ PlyWriteNum ];
|
|
template< typename Real , int Dim , typename Data , typename RealOnDisk >
|
|
void PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_SetReadProperties( void )
|
|
{
|
|
{
|
|
const PlyProperty * ReadProps = PlyVertex< Real , Dim , RealOnDisk >::PlyReadProperties();
|
|
for( int d=0 ; d<PlyVertex< Real , Dim , RealOnDisk >::PlyReadNum ; d++ ) _PlyReadProperties[d] = ReadProps[d];
|
|
}
|
|
{
|
|
const PlyProperty * ReadProps = Data::PlyReadProperties();
|
|
for( int d=0 ; d<Data::PlyReadNum ; d++ )
|
|
{
|
|
_PlyReadProperties[d+PlyVertex< Real , Dim , RealOnDisk >::PlyReadNum ] = ReadProps[d];
|
|
_PlyReadProperties[d+PlyVertex< Real , Dim , RealOnDisk >::PlyReadNum ].offset += (int)offsetof( PlyVertexWithData , data );
|
|
}
|
|
}
|
|
}
|
|
template< typename Real , int Dim , typename Data , typename RealOnDisk >
|
|
void PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_SetWriteProperties( void )
|
|
{
|
|
{
|
|
const PlyProperty * WriteProps = PlyVertex< Real , Dim , RealOnDisk >::PlyWriteProperties();
|
|
for( int d=0 ; d<PlyVertex< Real , Dim , RealOnDisk >::PlyWriteNum ; d++ ) _PlyWriteProperties[d] = WriteProps[d];
|
|
}
|
|
{
|
|
const PlyProperty * WriteProps = Data::PlyWriteProperties();
|
|
for( int d=0 ; d<Data::PlyWriteNum ; d++ )
|
|
{
|
|
_PlyWriteProperties[d+PlyVertex< Real , Dim , RealOnDisk >::PlyWriteNum ] = WriteProps[d];
|
|
_PlyWriteProperties[d+PlyVertex< Real , Dim , RealOnDisk >::PlyWriteNum ].offset += (int)offsetof( PlyVertexWithData , data );
|
|
}
|
|
}
|
|
}
|
|
|
|
template< class Vertex , class Real , int Dim >
|
|
int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex >* mesh , int file_type , const Point< float , Dim >& translate , float scale , const std::vector< std::string >& comments , XForm< Real , Dim+1 > xForm=XForm< Real , Dim+1 >::Identity() );
|
|
|
|
template< class Vertex , class Real , int Dim >
|
|
int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex >* mesh , int file_type , const std::vector< std::string >& comments , XForm< Real , Dim+1 > xForm=XForm< Real , Dim+1 >::Identity() );
|
|
|
|
inline bool PlyReadHeader( char* fileName , const PlyProperty* properties , int propertyNum , bool* readFlags , int& file_type )
|
|
{
|
|
std::vector< std::string > elist;
|
|
float version;
|
|
|
|
PlyFile *ply = PlyFile::Read( fileName , elist , file_type , version );
|
|
if( !ply ) return false;
|
|
|
|
for( int i=0 ; i<elist.size() ; i++ ) if( elist[i]=="vertex" ) for( int j=0 ; j<propertyNum ; j++ ) if( readFlags ) readFlags[j] = ply->get_property( elist[i].c_str() , &properties[j] )!=0;
|
|
|
|
delete ply;
|
|
return true;
|
|
}
|
|
inline bool PlyReadHeader( char* fileName , const PlyProperty* properties , int propertyNum , bool* readFlags )
|
|
{
|
|
int file_type;
|
|
return PlyReadHeader( fileName , properties , propertyNum , readFlags , file_type );
|
|
}
|
|
|
|
|
|
template< class Vertex >
|
|
int PlyReadPolygons( const char* fileName,
|
|
std::vector< Vertex >& vertices , std::vector<std::vector<int> >& polygons ,
|
|
const PlyProperty* properties , int propertyNum ,
|
|
int& file_type ,
|
|
std::vector< std::string > &comments , bool* readFlags=NULL );
|
|
|
|
template<class Vertex>
|
|
int PlyWritePolygons( const char* fileName ,
|
|
const std::vector< Vertex > &vertices , const std::vector< std::vector< int > > &polygons ,
|
|
const PlyProperty* properties , int propertyNum ,
|
|
int file_type ,
|
|
const std::vector< std::string > &comments );
|
|
|
|
template< class Vertex >
|
|
int PlyWritePolygons( const char* fileName ,
|
|
const std::vector< Vertex > &vertices , const std::vector< std::vector< int > > &polygons ,
|
|
const PlyProperty *properties , int propertyNum ,
|
|
int file_type ,
|
|
const std::vector< std::string > &comments )
|
|
{
|
|
int nr_vertices=int(vertices.size());
|
|
int nr_faces=int(polygons.size());
|
|
float version;
|
|
std::vector< std::string > elem_names = { std::string( "vertex" ) , std::string( "face" ) };
|
|
PlyFile *ply = PlyFile::Write( fileName , elem_names , file_type , version );
|
|
if (!ply){return 0;}
|
|
|
|
//
|
|
// describe vertex and face properties
|
|
//
|
|
ply->element_count( "vertex", nr_vertices );
|
|
for( int i=0 ; i<propertyNum ; i++ ) ply->describe_property( "vertex" , &properties[i] );
|
|
ply->element_count( "face" , nr_faces );
|
|
ply->describe_property( "face" , &face_props[0] );
|
|
|
|
// Write in the comments
|
|
for( int i=0 ; i<comments.size() ; i++ ) ply->put_comment( comments[i] );
|
|
ply->header_complete();
|
|
|
|
// write vertices
|
|
ply->put_element_setup( elem_names[0] );
|
|
for( int i=0 ; i<(int)vertices.size() ; i++ ) ply->put_element( (void *)&vertices[i] );
|
|
|
|
// write faces
|
|
PlyFace ply_face;
|
|
int maxFaceVerts=3;
|
|
ply_face.nr_vertices = 3;
|
|
ply_face.vertices = new int[3];
|
|
|
|
ply->put_element_setup( elem_names[1] );
|
|
for( int i=0 ; i<nr_faces ; i++ )
|
|
{
|
|
if( (int)polygons[i].size()>maxFaceVerts )
|
|
{
|
|
delete[] ply_face.vertices;
|
|
maxFaceVerts = (int)polygons[i].size();
|
|
ply_face.vertices=new int[ maxFaceVerts ];
|
|
}
|
|
ply_face.nr_vertices = (int)polygons[i].size();
|
|
for( int j=0 ; j<ply_face.nr_vertices ; j++ ) ply_face.vertices[j] = polygons[i][j];
|
|
ply->put_element( (void *)&ply_face );
|
|
}
|
|
|
|
delete[] ply_face.vertices;
|
|
delete ply;
|
|
|
|
return 1;
|
|
}
|
|
template< class Vertex >
|
|
int PlyReadPolygons( const char *fileName ,
|
|
std::vector< Vertex > &vertices , std::vector< std::vector< int > > &polygons ,
|
|
const PlyProperty *properties , int propertyNum ,
|
|
int &file_type ,
|
|
std::vector< std::string > &comments , bool *readFlags )
|
|
{
|
|
std::vector< std::string > elist;
|
|
float version;
|
|
|
|
PlyFile *ply = PlyFile::Read( fileName , elist , file_type , version );
|
|
if(!ply) return 0;
|
|
|
|
comments.reserve( comments.size() + ply->comments.size() );
|
|
for( int i=0 ; i<ply->comments.size() ; i++ ) comments.push_back( ply->comments[i] );
|
|
|
|
for( int i=0 ; i<elist.size() ; i++ )
|
|
{
|
|
std::string &elem_name = elist[i];
|
|
int num_elems;
|
|
std::vector< PlyProperty * > plist = ply->get_element_description( elem_name , num_elems );
|
|
if( !plist.size() )
|
|
{
|
|
delete ply;
|
|
return 0;
|
|
}
|
|
if( elem_name=="vertex" )
|
|
{
|
|
for( int i=0 ; i<propertyNum ; i++)
|
|
{
|
|
int hasProperty = ply->get_property( elem_name , &properties[i] );
|
|
if( readFlags ) readFlags[i] = (hasProperty!=0);
|
|
}
|
|
vertices.resize( num_elems );
|
|
for( int j=0 ; j<num_elems ; j++ ) ply->get_element( (void *)&vertices[j] );
|
|
}
|
|
else if( elem_name=="face" )
|
|
{
|
|
ply->get_property( elem_name , &face_props[0] );
|
|
polygons.resize( num_elems );
|
|
for( int j=0 ; j<num_elems ; j++ )
|
|
{
|
|
PlyFace ply_face;
|
|
ply->get_element( (void *)&ply_face );
|
|
polygons[j].resize( ply_face.nr_vertices );
|
|
for( int k=0 ; k<ply_face.nr_vertices ; k++ ) polygons[j][k] = ply_face.vertices[k];
|
|
free( ply_face.vertices );
|
|
} // for, read faces
|
|
} // if face
|
|
else ply->get_other_element( elem_name , num_elems );
|
|
|
|
for( int j=0 ; j<plist.size() ; j++ ) delete plist[j];
|
|
} // for each type of element
|
|
|
|
delete ply;
|
|
return 1;
|
|
}
|
|
|
|
template< class Vertex , class Real , int Dim >
|
|
int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex >* mesh , int file_type , const Point< float , Dim >& translate , float scale , const std::vector< std::string > &comments , XForm< Real , Dim+1 > xForm )
|
|
{
|
|
int nr_vertices=int(mesh->outOfCorePointCount()+mesh->inCorePoints.size());
|
|
int nr_faces=mesh->polygonCount();
|
|
float version;
|
|
std::vector< std::string > elem_names = { std::string( "vertex" ) , std::string( "face" ) };
|
|
PlyFile *ply = PlyFile::Write( fileName , elem_names , file_type , version );
|
|
if( !ply ) return 0;
|
|
|
|
mesh->resetIterator();
|
|
|
|
//
|
|
// describe vertex and face properties
|
|
//
|
|
ply->element_count( "vertex" , nr_vertices );
|
|
for( int i=0 ; i<Vertex::Components ; i++ ) ply->describe_property( "vertex" , &Vertex::Properties[i] );
|
|
ply->element_count( "face" , nr_faces );
|
|
ply->describe_property( "face" , &face_props[0] );
|
|
|
|
// Write in the comments
|
|
for( int i=0 ; i<comments.size() ; i++ ) ply->put_comment( comments[i] );
|
|
ply->header_complete();
|
|
|
|
// write vertices
|
|
ply->put_element_setup( "vertex" );
|
|
for( int i=0 ; i<int( mesh->inCorePoints.size() ) ; i++ )
|
|
{
|
|
Vertex vertex = xForm * ( mesh->inCorePoints[i] * scale + translate );
|
|
ply->put_element( (void *)&vertex );
|
|
}
|
|
for( int i=0; i<mesh->outOfCorePointCount() ; i++ )
|
|
{
|
|
Vertex vertex;
|
|
mesh->nextOutOfCorePoint( vertex );
|
|
vertex = xForm * ( vertex * scale + translate );
|
|
ply->put_element( (void *)&vertex );
|
|
} // for, write vertices
|
|
|
|
// write faces
|
|
std::vector< CoredVertexIndex > polygon;
|
|
ply->put_element_setup( "face" );
|
|
for( int i=0 ; i<nr_faces ; i++ )
|
|
{
|
|
//
|
|
// create and fill a struct that the ply code can handle
|
|
//
|
|
PlyFace ply_face;
|
|
mesh->nextPolygon( polygon );
|
|
ply_face.nr_vertices = int( polygon.size() );
|
|
ply_face.vertices = new int[ polygon.size() ];
|
|
for( int j=0 ; j<int(polygon.size()) ; j++ )
|
|
if( polygon[j].inCore ) ply_face.vertices[j] = polygon[j].idx;
|
|
else ply_face.vertices[j] = polygon[j].idx + int( mesh->inCorePoints.size() );
|
|
ply->put_element( (void *)&ply_face );
|
|
delete[] ply_face.vertices;
|
|
} // for, write faces
|
|
|
|
delete ply;
|
|
|
|
return 1;
|
|
}
|
|
template< class Vertex , class Real , int Dim >
|
|
int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex >* mesh , int file_type , const std::vector< std::string > &comments , XForm< Real , Dim+1 > xForm )
|
|
{
|
|
int nr_vertices=int(mesh->outOfCorePointCount()+mesh->inCorePoints.size());
|
|
int nr_faces=mesh->polygonCount();
|
|
float version;
|
|
std::vector< std::string > elem_names = { std::string( "vertex" ) , std::string( "face" ) };
|
|
PlyFile *ply = PlyFile::Write( fileName , elem_names , file_type , version );
|
|
if( !ply ) return 0;
|
|
|
|
mesh->resetIterator();
|
|
|
|
//
|
|
// describe vertex and face properties
|
|
//
|
|
ply->element_count( "vertex" , nr_vertices );
|
|
typename Vertex::Transform _xForm( xForm );
|
|
const PlyProperty* PlyWriteProperties = Vertex::PlyWriteProperties();
|
|
for( int i=0 ; i<Vertex::PlyWriteNum ; i++ ) ply->describe_property( "vertex" , &PlyWriteProperties[i] );
|
|
ply->element_count( "face" , nr_faces );
|
|
ply->describe_property( "face" , &face_props[0] );
|
|
|
|
// Write in the comments
|
|
for( int i=0 ; i<comments.size() ; i++ ) ply->put_comment( comments[i] );
|
|
ply->header_complete();
|
|
// write vertices
|
|
ply->put_element_setup( "vertex" );
|
|
for( int i=0 ; i<int( mesh->inCorePoints.size() ) ; i++ )
|
|
{
|
|
Vertex vertex = _xForm( mesh->inCorePoints[i] );
|
|
ply->put_element( (void *)&vertex );
|
|
}
|
|
for( int i=0; i<mesh->outOfCorePointCount() ; i++ )
|
|
{
|
|
Vertex vertex;
|
|
mesh->nextOutOfCorePoint( vertex );
|
|
vertex = _xForm( vertex );
|
|
ply->put_element( (void *)&vertex );
|
|
} // for, write vertices
|
|
|
|
// write faces
|
|
std::vector< CoredVertexIndex > polygon;
|
|
ply->put_element_setup( "face" );
|
|
for( int i=0 ; i<nr_faces ; i++ )
|
|
{
|
|
//
|
|
// create and fill a struct that the ply code can handle
|
|
//
|
|
PlyFace ply_face;
|
|
mesh->nextPolygon( polygon );
|
|
ply_face.nr_vertices = int( polygon.size() );
|
|
ply_face.vertices = new int[ polygon.size() ];
|
|
for( int j=0 ; j<int(polygon.size()) ; j++ )
|
|
if( polygon[j].inCore ) ply_face.vertices[j] = polygon[j].idx;
|
|
else ply_face.vertices[j] = polygon[j].idx + int( mesh->inCorePoints.size() );
|
|
ply->put_element( (void *)&ply_face );
|
|
delete[] ply_face.vertices;
|
|
} // for, write faces
|
|
|
|
delete ply;
|
|
|
|
return 1;
|
|
}
|
|
inline int PlyDefaultFileType(void){return PLY_ASCII;}
|
|
|
|
#endif /* !__PLY_H__ */
|