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.
381 lines
9.6 KiB
381 lines
9.6 KiB
/**************************************************************************** |
|
* VCGLib o o * |
|
* Visual and Computer Graphics Library o o * |
|
* _ O _ * |
|
* Copyright(C) 2004-2016 \/)\/ * |
|
* Visual Computing Lab /\/| * |
|
* ISTI - Italian National Research Council | * |
|
* \ * |
|
* All rights reserved. * |
|
* * |
|
* This program is free software; you can redistribute it and/or modify * |
|
* it under the terms of the GNU General Public License as published by * |
|
* the Free Software Foundation; either version 2 of the License, or * |
|
* (at your option) any later version. * |
|
* * |
|
* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) * |
|
* for more details. * |
|
* * |
|
****************************************************************************/ |
|
/**************************************************************************** |
|
Acknowlegments |
|
Portions of this file were based on the original code of the Ply library |
|
of Greg Turk and on the work of Claudio Rocchini |
|
|
|
****************************************************************************/ |
|
|
|
|
|
#ifndef __VCG_PLYLIB_STUFF |
|
#define __VCG_PLYLIB_STUFF |
|
|
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
#include <fcntl.h> |
|
#ifdef WIN32 |
|
#include <io.h> |
|
#else |
|
#include <unistd.h> |
|
#endif |
|
|
|
|
|
#include <vcg/space/box3.h> |
|
#include <wrap/ply/plylib.h> |
|
using namespace vcg; |
|
|
|
#ifdef WIN32 |
|
#include <direct.h> |
|
#define pb_mkdir(n) _mkdir(n) |
|
#define pb_access _access |
|
#define pb_stat _stat |
|
#define pb_fstat _fstat |
|
#define pb_open _open |
|
#define pb_close _close |
|
#define DIR_SEP "\\" |
|
#else |
|
#define pb_mkdir(n) mkdir(n,0755) |
|
#define pb_access access |
|
#define pb_stat stat |
|
#define pb_fstat fstat |
|
#define pb_open open |
|
#define pb_close close |
|
#define _O_BINARY 0 // Does not exist on Unix |
|
#define _O_RDONLY O_RDONLY |
|
#define DIR_SEP "/" |
|
#endif |
|
|
|
|
|
namespace vcg { |
|
namespace ply { |
|
|
|
const int MAXBPATH = 256; |
|
|
|
// Stringhe per la cache |
|
const char * cachedir = "vcg_cache"; |
|
const char * bboxcacheext = ".bbox_cache"; |
|
const char * bboxheader = "BBOXCACH"; |
|
|
|
bool GetDirFromPath( const char * path, char * dir, char * name ) |
|
{ |
|
strcpy(dir,path); |
|
char * p; |
|
|
|
p = strrchr(dir,'\\'); |
|
if(p==0) p=strrchr(dir,'/'); |
|
if(p==0) |
|
{ |
|
dir[0] = 0; |
|
strcpy(name,path); |
|
} |
|
else |
|
{ |
|
strcpy(name,p+1); |
|
*p = 0; |
|
} |
|
return true; |
|
} |
|
|
|
|
|
static bool CheckCacheDirectory( const char * dir ) |
|
{ |
|
if( pb_access(dir,0)!=0 ) |
|
{ |
|
if( pb_mkdir(dir)==-1 ) |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
|
|
bool CheckCacheTime( const char * fname, const char * cname ) |
|
{ |
|
|
|
if( pb_access(fname,4)==-1 ) return false; |
|
if( pb_access(cname,4)==-1 ) return false; |
|
|
|
int h,r; |
|
struct pb_stat st; |
|
time_t ft,bt; |
|
|
|
h = pb_open(fname,_O_BINARY|_O_RDONLY); |
|
if(h==0) return false; |
|
r = pb_fstat(h,&st); |
|
pb_close(h); |
|
if(r==-1) return false; |
|
ft = st.st_mtime; |
|
|
|
h = pb_open(cname,_O_BINARY|_O_RDONLY); |
|
if(h==0) return false; |
|
r = pb_fstat(h,&st); |
|
//_read(h,&box,sizeof(box)); |
|
pb_close(h); |
|
if(r==-1) return false; |
|
bt = st.st_mtime; |
|
|
|
if( difftime(bt,ft)>=0 ) return true; |
|
else return false; |
|
} |
|
|
|
// restituisce true se il file con la cache del bbox della mesh e' piu' recente del file ply |
|
// se fname2 != 0, allora deve essere piu recente anche di fname2. |
|
template<class ScalarType> |
|
static bool CheckBBoxCache( const char * fname, Box3<ScalarType> & box, const char *fname2=0 ) |
|
{ |
|
char d[MAXBPATH]; |
|
char n[MAXBPATH]; |
|
char h[8]; |
|
|
|
// Estrazione dati |
|
if( ! GetDirFromPath(fname,d,n) ) return false; |
|
|
|
// Controllo esistenza directory delle cache |
|
if(d[0]!=0) |
|
strcat(d,DIR_SEP); |
|
strcat(d,cachedir); |
|
if( !CheckCacheDirectory(d) ) return false; |
|
|
|
// Controllo esistenza e data file cache |
|
strcat(d,DIR_SEP); |
|
strcat(d,n); |
|
strcat(d,bboxcacheext); |
|
if( CheckCacheTime(fname,d) && |
|
(fname2==0 || CheckCacheTime(fname2,d)) ) |
|
{ |
|
// Lettura bbox e controllo |
|
Box3d readBB; |
|
FILE * fp = fopen(d,"rb"); |
|
if(fp==0) return false; |
|
if( fread(h,1,8,fp)!=8 ) |
|
{ |
|
fclose(fp); |
|
return false; |
|
} |
|
if( fread(&readBB,sizeof(Box3d),1,fp)!=1 ) |
|
{ |
|
fclose(fp); |
|
return false; |
|
} |
|
fclose(fp); |
|
box.Import(readBB); |
|
if( strncmp(h,bboxheader,8) ) |
|
return false; |
|
else |
|
return true; |
|
} |
|
else |
|
return false; |
|
} |
|
|
|
|
|
bool GetCacheName( const char * fname, const char * ext_name, char * cname ) |
|
{ |
|
static char n[MAXBPATH]; |
|
|
|
// Estrazione dati |
|
if( ! GetDirFromPath(fname,cname,n) ) return false; |
|
|
|
// Controllo esistenza directory delle cache |
|
if(cname[0]!=0) |
|
strcat(cname,DIR_SEP); |
|
strcat(cname,cachedir); |
|
if( !CheckCacheDirectory(cname) ) return false; |
|
|
|
strcat(cname,DIR_SEP); |
|
strcat(cname,n); |
|
strcat(cname,ext_name); |
|
return true; |
|
} |
|
|
|
|
|
template <class ScalarType> |
|
static bool SaveBBoxCache( const char * fname, const Box3<ScalarType> & boxOut ) |
|
{ |
|
char d[MAXBPATH]; |
|
|
|
Box3d box; |
|
box.Import(boxOut); |
|
if( !GetCacheName(fname,bboxcacheext,d) ) |
|
return false; |
|
|
|
// Lettura bbox e controllo |
|
FILE * fp = fopen(d,"wb"); |
|
if(fp==0) return false; |
|
if( fwrite(bboxheader,1,8,fp)!=8 ) |
|
{ |
|
fclose(fp); |
|
return false; |
|
} |
|
if( fwrite(&box,sizeof(Box3d),1,fp)!=1 ) |
|
{ |
|
fclose(fp); |
|
return false; |
|
} |
|
fclose(fp); |
|
return true; |
|
} |
|
|
|
struct PlyPoint3d |
|
{ |
|
double x; |
|
double y; |
|
double z; |
|
}; |
|
|
|
|
|
// Calcola il bbox di un file ply |
|
template <class ScalarType> |
|
bool ScanBBox( const char * fname, Box3<ScalarType> & box, bool use_cache=true ) |
|
{ |
|
|
|
if(use_cache) |
|
{ |
|
if( CheckBBoxCache(fname,box) ) |
|
return true; |
|
} |
|
|
|
static const PropDescriptor pv[3]= |
|
{ |
|
{"vertex","x",T_FLOAT,T_DOUBLE,offsetof(PlyPoint3d,x),0,0,0,0,0 ,0}, // TO GET RID OF COMPILER WARNING I ADDED 0 TO INITIALIZE format (MV) |
|
{"vertex","y",T_FLOAT,T_DOUBLE,offsetof(PlyPoint3d,y),0,0,0,0,0 ,0}, // TO GET RID OF COMPILER WARNING I ADDED 0 TO INITIALIZE format (MV) |
|
{"vertex","z",T_FLOAT,T_DOUBLE,offsetof(PlyPoint3d,z),0,0,0,0,0, 0},// TO GET RID OF COMPILER WARNING I ADDED 0 TO INITIALIZE format (MV) |
|
}; |
|
|
|
|
|
PlyFile pf; |
|
|
|
if( pf.Open(fname,PlyFile::MODE_READ)==-1 ) |
|
{ |
|
fprintf(stderr,"Warning: File %s not found\n",fname); |
|
return false; |
|
} |
|
|
|
if( pf.AddToRead(pv[0])==-1 ) { fprintf(stderr,"Warning: Read error\n"); return false; } |
|
if( pf.AddToRead(pv[1])==-1 ) { fprintf(stderr,"Warning: Read error\n"); return false; } |
|
if( pf.AddToRead(pv[2])==-1 ) { fprintf(stderr,"Warning: Read error\n"); return false; } |
|
|
|
box.SetNull(); |
|
char dummyspace[1024]; // sperando basti... |
|
|
|
for(int i=0;i<int(pf.elements.size());++i) |
|
{ |
|
int n = pf.ElemNumber(i); |
|
pf.SetCurElement(i); |
|
|
|
if( !strcmp( pf.ElemName(i),"vertex" ) ) |
|
{ |
|
for(int j=0;j<n;++j) |
|
{ |
|
PlyPoint3d t; |
|
|
|
pf.Read( (void *)(&t) ); |
|
box.Add( Point3<ScalarType>(t.x,t.y,t.z) ); |
|
} |
|
} |
|
else |
|
{ |
|
for(int j=0;j<n;++j) |
|
//pf.Read( 0 ); // prima era cosi' e faceva un'assert e scrivema plausibilimente a caso in mem |
|
pf.Read( dummyspace ); |
|
} |
|
} |
|
|
|
if(use_cache) |
|
{ |
|
SaveBBoxCache(fname,box); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
// Come la precedente ma applica la matrice m ai punti prima di calcolare il bbox. |
|
// Visto che la matrice di solito e' tenuta in un qualche file, se si vuole usare la cache |
|
// si puo' passare anche un'altro filename da controllare |
|
template <class ScalarType> |
|
bool ScanBBox( const char * fname, Box3<ScalarType> & box, const Matrix44<ScalarType> & m, bool use_cache, const char *matrixfname) |
|
{ |
|
|
|
if(use_cache) |
|
{ |
|
if ( CheckBBoxCache(fname,box,matrixfname) ) return true; |
|
} |
|
|
|
static const PropDescriptor pv[3]= |
|
{ |
|
{"vertex","x",T_FLOAT,T_DOUBLE,offsetof(PlyPoint3d,x),0,0,0,0,0, 0},// TO GET RID OF COMPILER WARNING I ADDED 0 TO INITIALIZE format (MV) |
|
{"vertex","y",T_FLOAT,T_DOUBLE,offsetof(PlyPoint3d,y),0,0,0,0,0, 0},// TO GET RID OF COMPILER WARNING I ADDED 0 TO INITIALIZE format (MV) |
|
{"vertex","z",T_FLOAT,T_DOUBLE,offsetof(PlyPoint3d,z),0,0,0,0,0, 0},// TO GET RID OF COMPILER WARNING I ADDED 0 TO INITIALIZE format (MV) |
|
}; |
|
|
|
|
|
PlyFile pf; |
|
|
|
if( pf.Open(fname,PlyFile::MODE_READ)==-1 ) |
|
{ |
|
fprintf(stderr,"Warning: File %s not found\n",fname); |
|
return false; |
|
} |
|
|
|
if( pf.AddToRead(pv[0])==-1 ) { fprintf(stderr,"Warning: Read error\n"); return false; } |
|
if( pf.AddToRead(pv[1])==-1 ) { fprintf(stderr,"Warning: Read error\n"); return false; } |
|
if( pf.AddToRead(pv[2])==-1 ) { fprintf(stderr,"Warning: Read error\n"); return false; } |
|
|
|
box.SetNull(); |
|
char dummyspace[1024]; // sperando basti... |
|
|
|
for(int i=0;i<int(pf.elements.size());++i) |
|
{ |
|
int n = pf.ElemNumber(i); |
|
pf.SetCurElement(i); |
|
|
|
if( !strcmp( pf.ElemName(i),"vertex" ) ) |
|
{ |
|
for(int j=0;j<n;++j) |
|
{ |
|
PlyPoint3d t; |
|
|
|
pf.Read( (void *)(&t) ); |
|
box.Add( m*Point3<ScalarType>(t.x,t.y,t.z) ); |
|
} |
|
} |
|
else |
|
{ |
|
for(int j=0;j<n;++j) |
|
//pf.Read( 0 ); // prima era cosi' e faceva un'assert e scrivema plausibilimente a caso in mem |
|
pf.Read( dummyspace ); |
|
} |
|
} |
|
|
|
if(use_cache) |
|
{ |
|
SaveBBoxCache(fname,box); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
} // end namespace ply |
|
} // end namespace vcg |
|
#endif |
|
|
|
|