Back to index

salome-smesh  6.5.0
DriverSTL_R_SMDS_Mesh.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 #include <stdio.h>
00024 #include <gp_Pnt.hxx>
00025 //=======================================================================
00026 //function : HashCode
00027 //purpose  : 
00028 //=======================================================================
00029 inline Standard_Integer HashCode
00030   (const gp_Pnt& point,  Standard_Integer Upper)
00031 {
00032   union 
00033     {
00034     Standard_Real R[3];
00035     Standard_Integer I[6];
00036     } U;
00037 
00038   point.Coord(U.R[0],U.R[1],U.R[2]);  
00039 
00040   return ::HashCode(U.I[0]/23+U.I[1]/19+U.I[2]/17+U.I[3]/13+U.I[4]/11+U.I[5]/7,Upper);
00041 }
00042 static Standard_Real tab1[3];
00043 static Standard_Real tab2[3];
00044 //=======================================================================
00045 //function : IsEqual
00046 //purpose  : 
00047 //=======================================================================
00048 inline Standard_Boolean IsEqual
00049   (const gp_Pnt& point1, const gp_Pnt& point2)
00050 {
00051   point1.Coord(tab1[0],tab1[1],tab1[2]);  
00052   point2.Coord(tab2[0],tab2[1],tab2[2]);  
00053   return (memcmp(tab1,tab2,sizeof(tab1)) == 0);
00054 }
00055 #include "DriverSTL_R_SMDS_Mesh.h"
00056 
00057 #include "SMDS_Mesh.hxx"
00058 #include "SMDS_MeshElement.hxx"
00059 #include "SMDS_MeshNode.hxx"
00060 
00061 #include <OSD_Path.hxx>
00062 #include <OSD_File.hxx>
00063 #include <OSD_FromWhere.hxx>
00064 #include <OSD_Protection.hxx>
00065 #include <OSD_SingleProtection.hxx>
00066 #include <Standard_NoMoreObject.hxx>
00067 
00068 #include "utilities.h"
00069 
00070 static const int HEADER_SIZE           =  84;
00071 static const int SIZEOF_STL_FACET      =  50;
00072 //static const int STL_MIN_FILE_SIZE     = 284;
00073 static const int ASCII_LINES_PER_FACET =   7;
00074 
00075 
00076 //typedef NCollection_BaseCollection<SMDS_MeshNodePtr> DriverSTL_ColOfNodePtr;
00077 
00078 
00079 #include <NCollection_DataMap.hxx>
00080 typedef NCollection_DataMap<gp_Pnt,SMDS_MeshNode*> DriverSTL_DataMapOfPntNodePtr;
00081 //=======================================================================
00082 //function : DriverSTL_R_SMDS_Mesh
00083 //purpose  : 
00084 //=======================================================================
00085 
00086 DriverSTL_R_SMDS_Mesh::DriverSTL_R_SMDS_Mesh()
00087 {
00088   myIsCreateFaces = true;
00089   myIsAscii = Standard_True;
00090 }
00091 
00092 //=======================================================================
00093 //function : SetIsCreateFaces
00094 //purpose  : 
00095 //=======================================================================
00096 
00097 void DriverSTL_R_SMDS_Mesh::SetIsCreateFaces( const bool theIsCreate )
00098 { myIsCreateFaces = theIsCreate; }
00099 
00100 //=======================================================================
00101 //function : Perform
00102 //purpose  : 
00103 //=======================================================================
00104 
00105 Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::Perform()
00106 {
00107   Status aResult = DRS_OK;
00108 
00109   TCollection_AsciiString aFileName( (char *)myFile.c_str() );
00110   if ( aFileName.IsEmpty() ) {
00111     fprintf(stderr, ">> ERREOR : invalid file name \n");
00112     return DRS_FAIL;
00113   }
00114 
00115   filebuf fic;
00116   Standard_IStream is(&fic);
00117   if (!fic.open(aFileName.ToCString(),ios::in)) {
00118     fprintf(stderr, ">> ERROR : cannot open file %s \n", aFileName.ToCString());
00119     return DRS_FAIL;
00120   }
00121 
00122 
00123   OSD_Path aPath( aFileName );
00124   OSD_File file = OSD_File( aPath );
00125   file.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));
00126   unsigned char str[128];
00127   Standard_Integer lread,i;
00128   Standard_Address ach;
00129   ach = (Standard_Address)str;
00130   // we skip the header which is in Ascii for both modes
00131   file.Read(ach,HEADER_SIZE,lread);
00132 
00133   // we read 128 characters to detect if we have a non-ascii char
00134   file.Read(ach,sizeof(str),lread);
00135   
00136   myIsAscii = Standard_True;
00137   for (i = 0; i < lread; ++i) {
00138     if (str[i] > '~') {
00139       myIsAscii = Standard_False;
00140       break;
00141     }
00142   }
00143       
00144   file.Close();
00145 
00146   if ( !myMesh ) {
00147     fprintf(stderr, ">> ERREOR : cannot create mesh \n");
00148     return DRS_FAIL;
00149   }
00150 
00151   if ( myIsAscii )
00152     aResult = readAscii();
00153   else
00154     aResult = readBinary();
00155 
00156   return aResult;
00157 }
00158 
00159 // static methods
00160 
00161 static Standard_Real readFloat(OSD_File& theFile)
00162 {
00163   union {
00164     Standard_Boolean i; 
00165     Standard_ShortReal f;
00166   }u;
00167 
00168   char c[4];
00169   Standard_Address adr;
00170   adr = (Standard_Address)c;
00171   Standard_Integer lread;
00172   theFile.Read(adr,4,lread);
00173   u.i  =  c[0] & 0xFF;
00174   u.i |= (c[1] & 0xFF) << 0x08;
00175   u.i |= (c[2] & 0xFF) << 0x10;
00176   u.i |= (c[3] & 0xFF) << 0x18;
00177 
00178   return u.f;
00179 }
00180 
00181 static SMDS_MeshNode* addNode(const gp_Pnt& P,
00182                               DriverSTL_DataMapOfPntNodePtr& uniqnodes,
00183                               SMDS_Mesh* theMesh)
00184 {
00185   SMDS_MeshNode* node = 0;
00186   if ( uniqnodes.IsBound(P) ) {
00187     node = uniqnodes.Find(P);
00188   } else {
00189     node = theMesh->AddNode(P.X(), P.Y(), P.Z() );
00190     uniqnodes.Bind(P,node);
00191   }
00192   
00193   return node;
00194 }                                
00195 
00196 static SMDS_MeshNode* readNode(FILE* file,
00197                                DriverSTL_DataMapOfPntNodePtr& uniqnodes,
00198                                SMDS_Mesh* theMesh)
00199 {
00200   Standard_ShortReal coord[3];
00201   // reading vertex
00202   fscanf(file,"%*s %f %f %f\n",&coord[0],&coord[1],&coord[2]);
00203 
00204   gp_Pnt P(coord[0],coord[1],coord[2]);
00205   return addNode( P, uniqnodes, theMesh );
00206 }
00207 
00208 static SMDS_MeshNode* readNode(OSD_File& theFile,
00209                                DriverSTL_DataMapOfPntNodePtr& uniqnodes,
00210                                SMDS_Mesh* theMesh)
00211 {
00212   Standard_ShortReal coord[3];
00213   coord[0] = readFloat(theFile);
00214   coord[1] = readFloat(theFile);
00215   coord[2] = readFloat(theFile);
00216 
00217   gp_Pnt P(coord[0],coord[1],coord[2]);
00218   return addNode( P, uniqnodes, theMesh );
00219 }
00220 
00221 //=======================================================================
00222 //function : readAscii
00223 //purpose  : 
00224 //=======================================================================
00225 
00226 Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readAscii() const
00227 {
00228   Status aResult = DRS_OK;
00229   long ipos;
00230   Standard_Integer nbLines = 0;
00231 
00232   // Open the file 
00233   TCollection_AsciiString aFileName( (char *)myFile.c_str() );
00234   FILE* file = fopen(aFileName.ToCString(),"r");
00235   fseek(file,0L,SEEK_END);
00236   // get the file size
00237   long filesize = ftell(file);
00238   fclose(file);
00239   file = fopen(aFileName.ToCString(),"r");
00240   
00241   // count the number of lines
00242   for (ipos = 0; ipos < filesize; ++ipos) {
00243     if (getc(file) == '\n')
00244       nbLines++;
00245   }
00246 
00247   // go back to the beginning of the file
00248 //  fclose(file);
00249 //  file = fopen(aFileName.ToCString(),"r");
00250   rewind(file);
00251   
00252   Standard_Integer nbTri = (nbLines / ASCII_LINES_PER_FACET);
00253 
00254   DriverSTL_DataMapOfPntNodePtr uniqnodes;
00255   // skip header
00256   while (getc(file) != '\n');
00257 
00258   // main reading
00259   for (Standard_Integer iTri = 0; iTri < nbTri; ++iTri) {
00260 
00261     // skipping the facet normal
00262     Standard_ShortReal normal[3];
00263     fscanf(file,"%*s %*s %f %f %f\n",&normal[0],&normal[1],&normal[2]);
00264 
00265     // skip the keywords "outer loop"
00266     fscanf(file,"%*s %*s");
00267 
00268     // reading nodes
00269     SMDS_MeshNode* node1 = readNode( file, uniqnodes, myMesh );
00270     SMDS_MeshNode* node2 = readNode( file, uniqnodes, myMesh );
00271     SMDS_MeshNode* node3 = readNode( file, uniqnodes, myMesh );
00272 
00273     if (myIsCreateFaces)
00274       myMesh->AddFace(node1,node2,node3);
00275 
00276     // skip the keywords "endloop"
00277     fscanf(file,"%*s");
00278 
00279     // skip the keywords "endfacet"
00280     fscanf(file,"%*s");
00281   }
00282 
00283   fclose(file);
00284   return aResult;
00285 }
00286 
00287 //=======================================================================
00288 //function : readBinary
00289 //purpose  : 
00290 //=======================================================================
00291 
00292 Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readBinary() const
00293 {
00294   Status aResult = DRS_OK;
00295 
00296   char buftest[5];
00297   Standard_Address adr;
00298   adr = (Standard_Address)buftest;
00299 
00300   TCollection_AsciiString aFileName( (char *)myFile.c_str() );
00301   OSD_File aFile = OSD_File(OSD_Path( aFileName ));
00302   aFile.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));
00303 
00304   // the size of the file (minus the header size)
00305   // must be a multiple of SIZEOF_STL_FACET
00306 
00307   // compute file size
00308   Standard_Integer filesize = aFile.Size();
00309 
00310   if ( (filesize - HEADER_SIZE) % SIZEOF_STL_FACET !=0 
00311       // Commented to allow reading small files (ex: 1 face)
00312       /*|| (filesize < STL_MIN_FILE_SIZE)*/) {
00313     Standard_NoMoreObject::Raise("DriverSTL_R_SMDS_MESH::readBinary (wrong file size)");
00314   }
00315 
00316   // don't trust the number of triangles which is coded in the file
00317   // sometimes it is wrong, and with this technique we don't need to swap endians for integer
00318   Standard_Integer nbTri = ((filesize - HEADER_SIZE) / SIZEOF_STL_FACET);
00319 
00320   // skip the header
00321   aFile.Seek(HEADER_SIZE,OSD_FromBeginning);
00322 
00323   DriverSTL_DataMapOfPntNodePtr uniqnodes;
00324   Standard_Integer lread;
00325   
00326   for (Standard_Integer iTri = 0; iTri < nbTri; ++iTri) {
00327 
00328     // ignore normals
00329     readFloat(aFile);
00330     readFloat(aFile);
00331     readFloat(aFile);
00332 
00333     // read vertices
00334     SMDS_MeshNode* node1 = readNode( aFile, uniqnodes, myMesh );
00335     SMDS_MeshNode* node2 = readNode( aFile, uniqnodes, myMesh );
00336     SMDS_MeshNode* node3 = readNode( aFile, uniqnodes, myMesh );
00337 
00338     if (myIsCreateFaces)
00339       myMesh->AddFace(node1,node2,node3);
00340 
00341     // skip extra bytes
00342     aFile.Read(adr,2,lread);
00343   }
00344   aFile.Close();
00345   return aResult;
00346 }