You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

571 lines
11 KiB

5 months ago
/*
Class for reading PLY (asc or binary) files
* for PLY specification, see http://www.ics.uci.edu/~graphics/teaching/ply.html
Copyright (C) 2011 Tao Ju
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
(LGPL) as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PLYREADER_H
#define PLYREADER_H
#include "GeoCommon.h"
#include "ModelReader.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
const char typeName[11][10] = {"char","uchar","short","ushort","int","uint","float","double", "uint8", "float32", "int32"} ;
const int typeSize[11] = {1,1,2,2,4,4,4,8,1,4,4} ;
const int totalTypes = 11 ;
class PLYReader : public ModelReader
{
public:
// File handle
FILE* fin ;
// Number of triangles
int numTrians, curtrian ;
// Number of vertices
int numVerts, curvert ;
// Vertex array
float* vertarray ;
// Bounding box
float min[3], max[3] ;
float rawmin[3], rawmax[3] ;
// Size of box
float maxsize ;
// Types and info
int extraVertex ;
// Temporary array for non-triangle faces
int temparray[64] ;
int tottri, curtri ;
// Mode
int mode ; // 0 for asc, 1 for little-endian, 2 for big endian
// Mode
int vmode ;
// Offset for reading faces
long offset ;
public:
/// Constructor
PLYReader( char* fname, float scl )
{
if ( ! ( fin = fopen( fname, "rb" ) ) )
{
printf("Unable to open file %s\n", fname) ;
};
// Scan to get info
// printf("Scanning file for bounding box...\n");
// Parse header
int vmode = 0, lines = 0 ;
this->numTrians = this->numVerts = this->extraVertex = 0 ;
char seps[] = " ,\t\n\r ";
seps[5] = 10 ;
while ( 1 )
{
char header[1024] ;
fgets( header, 1024, fin ) ;
// printf("%s\n", header) ;
char* token = strtok( header, seps ) ;
// token[ strlen(token) - 1 ] = '\0' ;
// int comp = strcmp ( token, "end_header" ) ;
// printf("%s %d\n", token, comp ) ;
// char c = getchar() ;
if ( ! strcmp ( token, "end_header" ) )
{
// Header finished
// printf("End encountered!") ;
break ;
} else if ( ! strcmp( token, "format" ) )
{
// Format specification
token = strtok ( NULL, seps ) ;
if ( !strcmp ( token, "ascii" ) )
{
this->mode = 0 ;
}
else if ( ! strcmp ( token, "binary_big_endian") )
{
this->mode = 2 ;
}
else
{
this->mode = 1 ;
}
} else if ( ! strcmp( token, "element") )
{
vmode = 0 ;
lines = 0 ;
token = strtok( NULL, seps ) ;
if ( !strcmp( token, "vertex" ) )
{
// Vertex count
token = strtok( NULL, seps ) ;
sscanf( token, "%d", &(this->numVerts) ) ;
// Enter vertex mode
vmode = 1 ;
} else if ( !strcmp( token, "face" ) )
{
// Face count
token = strtok( NULL, seps ) ;
sscanf( token, "%d", &(this->numTrians) ) ;
// Enter face mode
vmode = 2 ;
}
} else if ( ! strcmp( token, "property" ) )
{
switch ( vmode )
{
case 1: // Vertex mode
if ( lines >= 3 )
{
// Extra storage for each vertex
token = strtok( NULL, seps ) ;
for ( int i = 0 ; i < totalTypes ; i ++ )
{
if ( ! strcmp( token, typeName[i] ) )
{
this->extraVertex += typeSize[i] ;
break ;
}
}
}
lines ++ ;
break ;
case 2: // Face mode
break ;
}
}
}
//printf("Header info: %d vertices, %d faces, %d extra bytes per vertex. At %d\n", this->numVerts, this->numTrians, this->extraVertex, ftell( fin ) );
this->vertarray = new float [ 3 * this->numVerts ] ;
// char c = getchar() ;
/*
float *ok= new float[ numVerts * 3 ] ;
char c = getchar() ;
return ;
this->vertarray = new float* [this->numVerts ] ;
int i ;
for ( i = 0 ; i < this->numVerts ; i ++ )
{
vertarray[i] = new float[4] ;
}
printf("Done");
*/
// Start reading vertices
int i ;
char temp[1024] ;
if ( mode > 0 )
{
for ( i = 0 ; i < this->numVerts ; i ++ )
{
int haveread = 0 ;
if ( ( haveread = fread( &(vertarray[ 3 * i ]), sizeof( float ), 3, fin ) ) != 3 )
{
if( feof( fin ) )
{
printf( "Read error %ld ", ftell( fin ) );
}
printf("%d\n", haveread ) ;
exit(0) ;
}
if ( mode == 2 )
{
// Flip bits
for ( int j = 0 ; j < 3 ; j ++ )
{
flipBits32( & (vertarray[3*i + j]) ) ;
}
}
/*
printf("%f %f %f\n", vertarray[i][0], vertarray[i][1], vertarray[i][2] ) ;
if ( i == 10 )
{
exit(0) ;
}
*/
// Read extra data
fread( temp, 1, this->extraVertex, fin ) ;
if ( i == 0 )
{
for ( int j = 0 ; j < 3 ; j ++ )
{
rawmin[j] = rawmax[j] = vertarray[3 * i + j] ;
}
}
else
{
for ( int k = 0 ; k < 3 ; k ++ )
{
if ( rawmin[k] > vertarray[3 * i + k] )
{
rawmin[k] = vertarray[3 * i + k] ;
}
if ( rawmax[k] < vertarray[3 * i + k] )
{
rawmax[k] = vertarray[3 * i + k] ;
}
}
}
}
}
else
{
// ASCII mode
for ( i = 0 ; i < this->numVerts ; i ++ )
{
fgets ( temp, 1024, fin ) ;
char seps[] = " ,\t\n";
char* token = strtok( temp, seps ) ;
sscanf( token, "%f", &(vertarray[ 3 * i ] ) ) ;
token = strtok( NULL, seps ) ;
sscanf( token, "%f", &(vertarray[ 3 * i + 1 ] ) ) ;
token = strtok( NULL, seps ) ;
sscanf( token, "%f", &(vertarray[ 3 * i + 2 ] ) ) ;
if ( i == 0 )
{
for ( int j = 0 ; j < 3 ; j ++ )
{
rawmin[j] = rawmax[j] = vertarray[3 * i + j] ;
}
}
else
{
for ( int k = 0 ; k < 3 ; k ++ )
{
if ( rawmin[k] > vertarray[3 * i + k] )
{
rawmin[k] = vertarray[3 * i + k] ;
}
if ( rawmax[k] < vertarray[3 * i + k] )
{
rawmax[k] = vertarray[3 * i + k] ;
}
}
}
}
}
maxsize = rawmax[0] - rawmin[0] ;
if ( rawmax[1] - rawmin[1] > maxsize )
{
maxsize = rawmax[1] - rawmin[1] ;
}
if ( rawmax[2] - rawmin[2] > maxsize )
{
maxsize = rawmax[2] - rawmin[2] ;
}
for ( i = 0 ; i < 3 ; i ++ )
{
min[i] = ( rawmax[i] + rawmin[i] ) / 2 - maxsize / 2 ;
max[i] = ( rawmax[i] + rawmin[i] ) / 2 + maxsize / 2 ;
}
// printf( "Low corner: %f %f %f High corner %f %f %f \n", min[0], min[1], min[2], max[0], max[1], max[2] );
// printf( "Maxdif: %f \n", maxsize );
// Scale
for ( i = 0 ; i < 3 ; i ++ )
{
min[i] -= maxsize * ( 1 / scl - 1 ) / 2 ;
}
maxsize *= ( 1 / scl ) ;
// Reset
this->offset = ftell( fin ) ;
curtrian = 0 ;
};
void reset( )
{
curtrian = 0 ;
curvert = 0 ;
curtri = 0 ;
tottri = 0 ;
fseek( fin, offset, SEEK_SET ) ;
}
/// Get next triangle
Triangle* getNextTriangle( )
{
if ( curtrian == numTrians )
{
return NULL ;
}
if ( curtri == tottri )
{
// Read next face
unsigned char num ;
if ( mode > 0 )
{
// Read number of vertices in the face
fread( &num, sizeof( unsigned char ), 1, fin ) ;
fread( temparray, sizeof( int ), num, fin ) ;
if ( mode == 2 )
{
for ( int i = 0 ; i < num ; i ++ )
{
flipBits32( &(temparray[i]) ) ;
}
}
// printf("%d\n", tottri) ;
// printf("\n") ;
// if ( curtrian == 10 ) exit(1) ;
}
else
{
char temp[1024] ;
fgets( temp, 1024, fin ) ;
char seps[] = " ,\t\n";
char* token = strtok( temp, seps ) ;
sscanf( token, "%d", &num ) ;
for ( int i = 0 ; i < num ; i ++ )
{
token = strtok( NULL, seps ) ;
sscanf( token, "%d", &(temparray[i]) ) ;
}
}
tottri = num - 2 ;
curtri = 0 ;
curtrian ++ ;
}
Triangle* t = new Triangle() ;
for ( int i = 0 ; i < 3 ; i ++ )
{
t->vt[0][i] = vertarray[ 3 * temparray[0] + i ] ;
t->vt[1][i] = vertarray[ 3 * temparray[curtri + 1] + i ] ;
t->vt[2][i] = vertarray[ 3 * temparray[curtri + 2] + i ] ;
}
curtri ++ ;
// printf("%d %d %d\n", temparray[0], temparray[curtri + 1], temparray[curtri + 2]);
return t ;
};
/// Get next triangle
int getNextTriangle( int ind[3] )
{
if ( curtrian == numTrians )
{
return 0 ;
}
if ( curtri == tottri )
{
// Read next face
unsigned char num ;
if ( mode > 0 )
{
// Read number of vertices in the face
fread( &num, sizeof( unsigned char ), 1, fin ) ;
// Read array of indices
fread( temparray, sizeof( int ), num, fin ) ;
if ( mode == 2 )
{
for ( int i = 0 ; i < num ; i ++ )
{
flipBits32( &(temparray[i]) ) ;
// printf("%d ", temparray[i]) ;
}
}
// printf("\n") ;
// if ( curtrian == 10 ) exit(1) ;
}
else
{
char temp[1024] ;
fgets( temp, 1024, fin ) ;
char seps[] = " ,\t\n";
char* token = strtok( temp, seps ) ;
sscanf( token, "%d", &num ) ;
for ( int i = 0 ; i < num ; i ++ )
{
token = strtok( NULL, seps ) ;
sscanf( token, "%d", &(temparray[i]) ) ;
}
}
tottri = num - 2 ;
curtri = 0 ;
curtrian ++ ;
}
ind[0] = temparray[0] ;
ind[1] = temparray[curtri + 1] ;
ind[2] = temparray[curtri + 2] ;
curtri ++ ;
return 1 ;
};
void printInfo ( )
{
printf("Vertices: %d Polygons: %d\n",this->numVerts, this->numTrians) ;
}
/// Get bounding box
float getBoundingBox ( float origin[3] )
{
for ( int i = 0 ; i < 3 ; i ++ )
{
origin[i] = min[i] ;
}
return maxsize ;
};
void getRawBoundingBox ( float low[3], float high[3] )
{
for ( int i = 0 ; i < 3 ; i ++ )
{
low[i] = rawmin[i] ;
high[i] = rawmax[i] ;
}
}
/// Get storage size
int getMemory ( )
{
return sizeof ( class PLYReader ) + this->numVerts * sizeof( float ) * 3 ;
};
// Flip bits
void flipBits32 ( void *x )
{
unsigned char *temp = (unsigned char *)x;
unsigned char swap;
swap = temp [ 0 ];
temp [ 0 ] = temp [ 3 ];
temp [ 3 ] = swap;
swap = temp [ 1 ];
temp [ 1 ] = temp [ 2 ];
temp [ 2 ] = swap;
}
void printBits32 ( void *x )
{
unsigned char *temp = (unsigned char *)x;
printf("%2x %2x %2x %2x\n", temp[0], temp[1], temp[2], temp[3]) ;
}
int getNumTriangles()
{
return this->numTrians ;
}
int getNumVertices()
{
return this->numVerts ;
}
float* getVertex( int ind )
{
return &(this->vertarray[ 3 * ind ]) ;
}
void getNextVertex( float v[3] )
{
v[0] = vertarray[ 3 * curvert ] ;
v[1] = vertarray[ 3 * curvert + 1 ] ;
v[2] = vertarray[ 3 * curvert + 2 ] ;
curvert ++ ;
}
int getMode( )
{
return this->mode ;
}
void close()
{
fclose( this->fin ) ;
}
};
#endif