00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef __VCGLIB_IMPORT_STL
00025 #define __VCGLIB_IMPORT_STL
00026 #include <stdio.h>
00027 #include <wrap/io_trimesh/io_mask.h>
00028
00029 namespace vcg {
00030 namespace tri {
00031 namespace io {
00032
00038 template <class OpenMeshType>
00039 class ImporterSTL
00040 {
00041 public:
00042
00043 typedef typename OpenMeshType::VertexPointer VertexPointer;
00044 typedef typename OpenMeshType::ScalarType ScalarType;
00045 typedef typename OpenMeshType::VertexType VertexType;
00046 typedef typename OpenMeshType::FaceType FaceType;
00047 typedef typename OpenMeshType::VertexIterator VertexIterator;
00048 typedef typename OpenMeshType::FaceIterator FaceIterator;
00049
00050
00051
00052 enum {STL_LABEL_SIZE=80};
00053
00054 class STLFacet
00055 {
00056 public:
00057 Point3f n;
00058 Point3f v[3];
00059
00060 };
00061
00062 enum STLError {
00063 E_NOERROR,
00064
00065 E_CANTOPEN,
00066 E_UNESPECTEDEOF
00067 };
00068
00069 static const char *ErrorMsg(int error)
00070 {
00071 static const char * stl_error_msg[] =
00072 {
00073 "No errors",
00074 "Can't open file",
00075 "Premature End of file",
00076 };
00077
00078 if(error>2 || error<0) return "Unknown error";
00079 else return stl_error_msg[error];
00080 };
00081
00082 static bool LoadMask(const char * filename, int &mask)
00083 {
00084 bool magicMode;
00085 mask = Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX;
00086 if(IsSTLColored(filename,magicMode))
00087 mask |= Mask::IOM_FACECOLOR;
00088 return true;
00089 }
00090
00091
00092
00093
00094
00095
00096
00097
00098 static bool IsSTLColored(const char * filename, bool &magicsMode)
00099 {
00100 if(IsSTLBinary(filename)==false)
00101 return false;
00102 FILE *fp = fopen(filename, "rb");
00103 char buf[STL_LABEL_SIZE+1];
00104 fread(buf,sizeof(char),STL_LABEL_SIZE,fp);
00105 std::string strInput(buf);
00106 size_t cInd = strInput.rfind("COLOR=");
00107 size_t mInd = strInput.rfind("MATERIAL=");
00108 if(cInd!=std::string::npos && mInd!=std::string::npos)
00109 magicsMode = true;
00110 else
00111 magicsMode = false;
00112 int facenum;
00113 fread(&facenum, sizeof(int), 1, fp);
00114
00115 for(int i=0;i<std::min(facenum,1000);++i)
00116 {
00117 unsigned short attr;
00118 Point3f norm;
00119 Point3f tri[3];
00120 fread(&norm,sizeof(Point3f),1,fp);
00121 fread(&tri,sizeof(Point3f),3,fp);
00122 fread(&attr,sizeof(unsigned short),1,fp);
00123 if(attr!=0)
00124 {
00125 if(Color4b::FromUnsignedR5G5B5(attr) != Color4b(Color4b::White))
00126 return true;
00127 }
00128 }
00129
00130 return false;
00131 }
00132
00133 static bool IsSTLBinary(const char * filename)
00134 {
00135 bool binary=false;
00136 FILE *fp = fopen(filename, "r");
00137
00138 fseek(fp, 0, SEEK_END);
00139 int file_size = ftell(fp);
00140 int facenum;
00141
00142 fseek(fp, STL_LABEL_SIZE, SEEK_SET);
00143 fread(&facenum, sizeof(int), 1, fp);
00144 int expected_file_size=STL_LABEL_SIZE + 4 + (sizeof(short)+sizeof(STLFacet) )*facenum ;
00145 if(file_size == expected_file_size) binary = true;
00146 unsigned char tmpbuf[128];
00147 fread(tmpbuf,sizeof(tmpbuf),1,fp);
00148 for(unsigned int i = 0; i < sizeof(tmpbuf); i++)
00149 {
00150 if(tmpbuf[i] > 127)
00151 {
00152 binary=true;
00153 break;
00154 }
00155 }
00156
00157 fclose(fp);
00158 return binary;
00159 }
00160
00161 static int Open( OpenMeshType &m, const char * filename, int &loadMask, CallBackPos *cb=0)
00162 {
00163 FILE *fp = fopen(filename, "r");
00164 if(fp == NULL)
00165 return E_CANTOPEN;
00166 fclose(fp);
00167 loadMask |= Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX;
00168
00169 if(IsSTLBinary(filename)) return OpenBinary(m,filename,loadMask,cb);
00170 else return OpenAscii(m,filename,cb);
00171 }
00172
00173 static int OpenBinary( OpenMeshType &m, const char * filename, int &loadMask, CallBackPos *cb=0)
00174 {
00175 FILE *fp;
00176 fp = fopen(filename, "rb");
00177 if(fp == NULL)
00178 {
00179 return E_CANTOPEN;
00180 }
00181
00182 bool magicsMode;
00183 if(!IsSTLColored(filename,magicsMode))
00184 loadMask = loadMask & (~Mask::IOM_FACECOLOR);
00185
00186 int facenum;
00187 fseek(fp, STL_LABEL_SIZE, SEEK_SET);
00188 fread(&facenum, sizeof(int), 1, fp);
00189
00190 m.Clear();
00191 FaceIterator fi=Allocator<OpenMeshType>::AddFaces(m,facenum);
00192 VertexIterator vi=Allocator<OpenMeshType>::AddVertices(m,facenum*3);
00193
00194 for(int i=0;i<facenum;++i)
00195 {
00196 unsigned short attr;
00197 Point3f norm;
00198 Point3f tri[3];
00199 fread(&norm,sizeof(Point3f),1,fp);
00200 fread(&tri,sizeof(Point3f),3,fp);
00201 fread(&attr,sizeof(unsigned short),1,fp);
00202 if(tri::HasPerFaceColor(m) && (loadMask & Mask::IOM_FACECOLOR) )
00203 {
00204 if(magicsMode) (*fi).C()= Color4b::FromUnsignedR5G5B5(attr);
00205 else (*fi).C()= Color4b::FromUnsignedB5G5R5(attr);
00206 }
00207 for(int k=0;k<3;++k)
00208 {
00209 (*vi).P().Import(tri[k]);
00210 (*fi).V(k)=&*vi;
00211 ++vi;
00212 }
00213 ++fi;
00214 if(cb && (i%1000)==0) cb((i*100)/facenum,"STL Mesh Loading");
00215 }
00216 fclose(fp);
00217 return E_NOERROR;
00218 }
00219
00220
00221 static int OpenAscii( OpenMeshType &m, const char * filename, CallBackPos *cb=0)
00222 {
00223 FILE *fp;
00224 fp = fopen(filename, "r");
00225 if(fp == NULL)
00226 {
00227 return E_CANTOPEN;
00228 }
00229 long currentPos = ftell(fp);
00230 fseek(fp,0L,SEEK_END);
00231 long fileLen = ftell(fp);
00232 fseek(fp,currentPos,SEEK_SET);
00233
00234 m.Clear();
00235
00236
00237 while(getc(fp) != '\n') { }
00238
00239 STLFacet f;
00240 int cnt=0;
00241 int lineCnt=0;
00242 int ret;
00243
00244 while(!feof(fp))
00245 {
00246 if(cb && (++cnt)%1000) cb( int(double(ftell(fp))*100.0/fileLen), "STL Mesh Loading");
00247 ret=fscanf(fp, "%*s %*s %f %f %f\n", &f.n.X(), &f.n.Y(), &f.n.Z());
00248 if(ret!=3)
00249 {
00250
00251
00252
00253
00254
00255
00256 lineCnt++;
00257 continue;
00258 }
00259 ret=fscanf(fp, "%*s %*s");
00260 ret=fscanf(fp, "%*s %f %f %f\n", &f.v[0].X(), &f.v[0].Y(), &f.v[0].Z());
00261 if(ret!=3)
00262 return E_UNESPECTEDEOF;
00263 ret=fscanf(fp, "%*s %f %f %f\n", &f.v[1].X(), &f.v[1].Y(), &f.v[1].Z());
00264 if(ret!=3)
00265 return E_UNESPECTEDEOF;
00266 ret=fscanf(fp, "%*s %f %f %f\n", &f.v[2].X(), &f.v[2].Y(), &f.v[2].Z());
00267 if(ret!=3)
00268 return E_UNESPECTEDEOF;
00269 ret=fscanf(fp, "%*s");
00270 ret=fscanf(fp, "%*s");
00271 lineCnt+=7;
00272 if(feof(fp)) break;
00273 FaceIterator fi=Allocator<OpenMeshType>::AddFaces(m,1);
00274 VertexIterator vi=Allocator<OpenMeshType>::AddVertices(m,3);
00275 for(int k=0;k<3;++k)
00276 {
00277 (*vi).P().Import(f.v[k]);
00278 (*fi).V(k)=&*vi;
00279 ++vi;
00280 }
00281 }
00282 fclose(fp);
00283 return E_NOERROR;
00284 }
00285 };
00286 }
00287 }
00288 }
00289
00290 #endif